尝试呈现 JSX 元素但未定义

Attempting to render JSX element but getting undefined

所以我尝试在 Class 组件中呈现这个 JSX 元素。它本质上是 D3 的 React 库提供的视觉效果。但是,我在尝试渲染 D3 视觉效果时收到此错误:

Unhandled Rejection (Error): Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

以下是错误发生位置的一些相关代码片段:

将所有必要的道具传递给 D3 库的构建器函数

const buildModelVisual = (dataPoints) => {
    console.log("category: " + dataPoints[0].category)
    console.log("range: " + dataPoints[0].range)
    console.log("frequency: " + dataPoints[0].frequency)
    dataPoints[0].frequency.forEach(f => 
        console.log("f: " + f)
    )
    const width = 960,
        height = 500,
        margins = {top: 50, right: 50, bottom: 50, left: 50},
        id = "model-visual",
        title = "NaiveBayes Model Visual",
        svgClassName = "model-visual-class",
        titleClassName = "model-visual-title-class",
        legendClassName = "model-legend",
        showLegend = true,
        showXAxis = true,
        showYAxis = true,
        showXGrid = false,
        showYGrid = false,
        ranges = [
            ...dataPoints[0].range
        ],
        frequencies = [
            ...dataPoints[0].frequency
        ],
        x = () => {
            return ranges.forEach(r => {
                return r;
            })
        },
        xOrient = 'bottom',
        xTickOrient = 'bottom'
    
    const xDomain = dataPoints[0].range.forEach(r => {
        return {
            category: dataPoints[0].category, range: r
        }
        }),
        xRangeRoundBands = {interval: [0, width - margins.left - margins.right], padding: 0.1},
        xScale = 'ordinal',
        xAxisClassName = 'x-axis',
        xLabel = dataPoints[0].category,
        xLabelPosition = 'bottom',
        xTickPadding = 3,
        xInnerTickSize = 6,
        xOuterTickSize = 6,
        y = () => {
            return frequencies.forEach(freqInRange => {
                return freqInRange.forEach(f => {
                    return f;
                });
            })
        },
        yOrient = 'left',
        yTickOrient = 'left',
        yRange = [height - margins.top - margins.bottom, 0]

    const yDomain = [0, d3.max(
            dataPoints[0].frequency,
            (f) => {
                return f.value
            }
        )],
        yScale = 'linear',
        yAxisClassName = 'y-axis',
        yLabel = "Population",
        yTickFormat = d3.format(".2s"),
        yLabelPosition = 'left',
        yTickPadding = 4,
        yInnerTickSize = 6,
        yOuterTickSize = 6

    return (
        <Chart
        title={title}
        id={id}
        width={width}
        height={height}
        >
        <BarStackChart
          title= {title}
          data= {ranges}
          width= {width}
          height= {height}
          id= {id}
          margins= {margins}
          svgClassName= {svgClassName}
          titleClassName= {titleClassName}
          yAxisClassName= {yAxisClassName}
          xAxisClassName= {xAxisClassName}
          legendClassName= {legendClassName}
          categoricalColors= {d3.scaleOrdinal(d3.schemeCategory10)}
          chartSeries = {ranges}
          showLegend= {showLegend}
          showXAxis= {showXAxis}
          showYAxis= {showYAxis}
          x= {x}
          showXGrid= {showXGrid}
          xDomain= {xDomain}
          xRangeRoundBands= {xRangeRoundBands}
          xScale= {xScale}
          xOrient= {xOrient}
          xTickOrient= {xTickOrient}
          xTickPadding = {xTickPadding}
          xInnerTickSize = {xInnerTickSize}
          xOuterTickSize = {xOuterTickSize}
          xLabel = {xLabel}
          xLabelPosition = {xLabelPosition}
          y= {y}
          showYGrid= {showYGrid}
          yOrient= {yOrient}
          yRange= {yRange}
          yDomain= {yDomain}
          yScale= {yScale}
          yTickOrient= {yTickOrient}
          yTickPadding = {yTickPadding}
          yInnerTickSize = {yInnerTickSize}
          yOuterTickSize = {yOuterTickSize}
          yTickFormat= {yTickFormat}
          yLabel = {yLabel}
          yLabelPosition = {yLabelPosition}
        />
      </Chart>
    )
}

正在呈现图形和界面的 HO class 组件

    constructor(props) {
        super(props);
        this.ref = React.createRef();
        this.state = {
            input: "",
            output: [],
            visual: null
        }
    }

REST API 调用(在默认 class 组件内)为 BarStackChart

设置数据
callGetModel = () => {
        let getModelRanges = getCall(ApiURL.get_model_ranges);
        let getModelFrequencies = getCall(ApiURL.get_model_frequencies);
        Promise.all([getModelRanges, getModelFrequencies]).then(data => {
            this.setState({output: data})
            const dataPoints = [];

            for (let value in JSON.parse(data[0].toString())) {
                dataPoints.push({
                    category: value,
                    range: JSON.parse(data[0].toString())[value],
                    frequency: JSON.parse(data[1].toString())[value]
                })
            }

            console.log(dataPoints)

            const ModelVisual = buildModelVisual(dataPoints)

            this.setState({ visual: ModelVisual }) // returns JSX element 

            console.log(this.state.visual)
        });
    }

class 组件的渲染方法

    render() {
        return <div>
            <h3>Welcome to Naive Bayes Java!</h3>
            <p>The REST API for this project is hosted at</p>
            <a style={{'display':'block', 'paddingBottom':'1.5em', 'color':'rgb(0, 150, 196)'}} href="https://naivebayesjava.herokuapp.com/swagger-ui.html#/">https://naivebayesjava.herokuapp.com/</a>
            <button style={{'display':'inline', 'background':'rgb(32, 32, 32)', 'color':'rgb(190, 190, 190)'}} onClick={this.callListOfFiles}>
                Get List of Valid Files
            </button>
            <button style={{'background':'rgb(32, 32, 32)', 'color':'rgb(190, 190, 190)'}} onClick={this.callGetModel}>
                Get Model
            </button>
            <button style={{'background':'rgb(32, 32, 32)', 'color':'rgb(190, 190, 190)'}} onClick={this.callGetModelAccuracy}>
                Get Model Accuracy
            </button>
            <div style={{'margin':'auto', 'display':'block'}}>
                <input style={{'background':'rgb(32, 32, 32)', 'color':'rgb(190, 190, 190)'}} type='text' value={this.state.input} onChange={this.handleChange}/>
                <button style={{'background':'rgb(32, 32, 32)', 'color':'rgb(190, 190, 190)'}} onClick={this.callSetData}>
                    Set Training Data File
                </button>
            </div>
            {/* <button onClick={this.callGetTrainingData}>
                Get Training Data Arff Files
            </button> */}
            <div style={{'padding-top':'0.5em'}} ref={this.ref}></div>
            <output type='textBox' style={{ 'padding':'1.25em', 'display':'block', 'Height': '30px', 'Width': '300px' }}>
            { Object.keys(this.state.output).map(key => {
                return this.state.output[key]                
            }) }
            </output>
            { this.state.visual }
        </div>
    }

除了设置“this.state.visual”JSX 元素并在 render 方法中调用它之外,绝对有更好的方法来实现它,尽管我对 React 都是新手(开始学习大约一个月前)和 JS(大约 3 个月前开始)我不太了解两者的所有常见做法;只是它们工作原理背后的一般理论。

此界面和我的作品集托管在 joshuabaroni.github.io。我试图改进的界面是“项目”部分下的 NaiveBayes 项目界面

如有任何建议,我们将不胜感激!整个 JS 文件可应要求提供。

You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

您没有按要求导出 classes/functions。

没有默认值的导出意味着它是“命名导出”。您可以在一个文件中有多个命名导出。所以如果你这样做,

class Template {}
class AnotherTemplate {}
export { Template, AnotherTemplate } // named export

然后您必须使用它们的确切名称导入这些导出。因此,要在另一个文件中使用这些组件,您必须这样做,

import {Template, AnotherTemplate} from './components/templates'

或者,如果您像这样导出为默认导出,

export default class Template {}

然后在另一个文件中导入默认导出而不使用 {},就像这样,

import Template from './components/templates'

每个文件只能有一个默认导出。在 React 中,从一个文件中导出一个组件是一种惯例,并且将其导出为默认导出。

您可以在导入时自由重命名默认导出,

import TheTemplate from './components/templates'

并且您可以同时导入默认导出和命名导出,

import Template,{AnotherTemplate} from './components/templates'