0

所以我有这个 JSX 元素,我试图在 Class 组件中呈现。它本质上是 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 类组件

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

为 BarStackChart 设置数据的 REST API 调用(在默认类 Component 中)

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)
        });
    }

类 Component 的渲染方法

    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 元素并在渲染方法中调用它之外,肯定有更好的方法来实现这一点,尽管我对 React(大约一个月前开始学习)和 JS(大约 3 个月前开始)我不太了解两者的所有常见做法;只是它们如何工作的一般理论。

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

任何建议将不胜感激!整个 JS 文件可根据要求提供。

4

1 回答 1

0

您可能忘记从定义组件的文件中导出组件,或者您可能混淆了默认导入和命名导入。

您没有按照需要导出您的类/函数。

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

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'
于 2020-08-18T19:02:40.467 回答