如何为我的React应用解决“元素类型无效”?

时间:2019-01-15 12:59:30

标签: javascript node.js reactjs material-ui

我正在尝试更好地构建我的初始代码。

https://codesandbox.io/s/jqvkqy29w

但是,我在集成子组件方面遇到问题。作为示例,我展示了如何导入子组件TopControls。另外,我不确定我是否正确导入了styles

下面,我显示一个主要根组件的代码。问题是页面为空,并且未加载TopControls。打开控制台时,看到以下警告和错误(我使用"react": "^16.6.0""react-dom": "^16.6.0")。

  

警告:React.createElement:类型无效-预期为字符串   (对于内置组件)或类/函数(对于复合   组件),但得到:对象。您可能忘记了导出   定义文件中的组件,否则您可能混淆了   默认导入和命名导入。

     

在Main.js:113中检查代码。       在_default中(在App.js:21)       在App中(位于src / index.js:5)

     

react-dom.development.js:57未捕获的错误:元素类型无效:   预期的字符串(用于内置组件)或类/函数(用于   复合组件),但得到了:对象。您可能忘记了出口   您的组件来自定义它的文件,或者您可能已经混合了   设置默认名称并命名导入。

     

检查_default的渲染方法。       不变(react-dom.development.js:57)       在createFiberFromTypeAndProps(react-dom.development.js:10531)       在createFiberFromElement(react-dom.development.js:10551)       在createChild(react-dom.development.js:13811)       在reconcileChildrenArray(react-dom.development.js:14080)       在reconcileChildFibers(react-dom.development.js:14430)       在reconcileChildren(react-dom.development.js:14817)       在finishClassComponent(react-dom.development.js:15161)       在updateClassComponent(react-dom.development.js:15096)       在beginWork(react-dom.development.js:15980)       在performUnitOfWork(react-dom.development.js:19102)       在workLoop(react-dom.development.js:19143)       在HTMLUnknownElement.callCallback(react-dom.development.js:147)       在Object.invokeGuardedCallbackDev(react-dom.development.js:196)       在invokeGuardedCallback(react-dom.development.js:250)       在replayUnitOfWork(react-dom.development.js:18350)       在renderRoot(react-dom.development.js:19261)       在performWorkOnRoot(react-dom.development.js:20165)       在performWork(react-dom.development.js:20075)       在performSyncWork(react-dom.development.js:20049)       在interactiveUpdates $ 1(react-dom.development.js:20337)       在InteractiveUpdates(react-dom.development.js:2267)       在dispatchInteractiveEvent(react-dom.development.js:5083)不变@ react-dom.development.js:57 createFiberFromTypeAndProps @   react-dom.development.js:10531 createFiberFromElement @   react-dom.development.js:10551 createChild @   react-dom.development.js:13811 reconcileChildrenArray @   react-dom.development.js:14080 reconcileChildFibers @   react-dom.development.js:14430 reconcileChildren @   react-dom.development.js:14817 finishClassComponent @   react-dom.development.js:15161 updateClassComponent @   react-dom.development.js:15096 beginWork @   react-dom.development.js:15980 performUnitOfWork @   react-dom.development.js:19102 workLoop @   react-dom.development.js:19143 callCallback @   react-dom.development.js:147 invokeGuardedCallbackDev @   react-dom.development.js:196 invokeGuardedCallback @   react-dom.development.js:250 replayUnitOfWork @   react-dom.development.js:18350 renderRoot @   react-dom.development.js:19261 performWorkOnRoot @   react-dom.development.js:20165 performWork @   react-dom.development.js:20075 performSyncWork @   react-dom.development.js:20049互动更新$ 1 @   react-dom.development.js:20337互动更新@   react-dom.development.js:2267 dispatchInteractiveEvent @   react-dom.development.js:5083 index.js:1446发生上述错误   在<_default>组件中:       在_default中(在App.js:21)       在App中(位于src / index.js:5)

根组件“ Main.js”:

import React, { Component, Fragment } from 'react';
import TopControls from "./layout/single/TopControls"
import styles from "./layout/single/styles"


export default class extends Component {

  constructor(props) {
      super(props);
      this.state = {
          holdingTime: 1,
          plannedDep: "2017-05-24T10:30",
          schedTurnd: 45,
          asma40: 100,
          asma60: 500,
          taxiInTime: 9.50,
          wake: 84.73,
          temperature: 20,
          visibility: 5999.66,
          windIntensity: 8.0,
          arrivalDelay: 5,
          distanceTarget: 500,
          airport: "LEBL",
          delay: 0,
          delay_probability: 0,
          delay_cat: "NA",
          chartDataWake: [],
          chartDataTurnaround: [],
          chartDataArrivalDelay: [],
          chartDataDistanceTarget: [],
          labelWidth: 0
      };
      this.handleChange = this.handleChange.bind(this);
  };

  componentDidMount() {
      this.fetchData();
  };

  updateDelay(predicted_delay,delay_probability) {
      this.state.chartDataWake = [...this.state.chartDataWake, {wake: this.state.wake===84.73 ? "H" : (this.state.wake===14.78 ? "M" : "L"), delay: predicted_delay}];
      this.state.chartDataTurnaround = [...this.state.chartDataTurnaround, {turnaround: this.state.schedTurnd, delay: predicted_delay}];
      this.state.chartDataArrivalDelay = [...this.state.chartDataArrivalDelay, {arrivalDelay: this.state.arrivalDelay, delay: predicted_delay}];
      this.state.chartDataDistanceTarget = [...this.state.chartDataDistanceTarget, {distanceTarget: this.state.distanceTarget, delay: predicted_delay}];
      this.setState({
        delay: predicted_delay,
        delay_probability: delay_probability,
        delay_cat: predicted_delay===0 ? "<15" : (predicted_delay===1 ? "[15; 45]" : ">45")
      });
  };

  fetchData = () => {
      const url = "http://localhost:8000?"+
        'holdingTime='+this.state.holdingTime+
        '&plannedDep='+this.state.plannedDep+
        '&schedTurnd='+this.state.schedTurnd+
        '&asma40='+this.state.asma40+
        '&asma60='+this.state.asma60+
        '&taxiInTime='+this.state.taxiInTime+
        '&wake='+this.state.wake+
        '&temperature='+this.state.temperature+
        '&visibility='+this.state.visibility+
        '&windIntensity='+this.state.windIntensity+
        '&arrivalDelay='+this.state.arrivalDelay+
        '&distanceTarget='+this.state.distanceTarget;

      fetch(url, {
        method: "GET",
        dataType: "JSON",
        headers: {
          "Content-Type": "application/json; charset=utf-8",
        }
      })
      .then((resp) => {
        return resp.json()
      })
      .then((data) => {
        this.updateDelay(data.prediction,data.probability)
      })
      .catch((error) => {
        console.log(error, "catch the hoop")
      })
  };

  handleChange = (name, event) => {
    this.setState({
      [name]: event.target.value
    }, () => {
      console.log("plannedDep",this.state.plannedDep)
    });
  };


  handleReset = () => {
      this.setState({
          chartDataWake: [],
          chartDataTurnaround: [],
          chartDataArrivalDelay: [],
          chartDataDistanceTarget: [],
          delay: 0,
          delay_probability: 0,
          delay_cat: "NA"
      });
  };

  render() {
    return <Fragment>

      <TopControls state={this.state} handleChange={this.handleChange} styles={styles} />

    </Fragment>
  }
}

styles.js

const styles = theme => ({
    header: {
        borderBottom: 'solid 1px rgba(0,0,0,0.4)',
        backgroundColor: '#253069',
        color: '#d2d6ef',
        overflow: 'hidden',
        boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
        position: 'relative',
        height: '12%'
    },
    h1: {
        fontSize: '30px',
        textAlign: 'center',
        fontFamily: 'sans-serif',
        lineHeight: '1.45em',
        webkitFontSmoothing: 'antialiased'
    },
    h3: {
        fontSize: '20px',
        textAlign: 'left',
        fontFamily: 'sans-serif',
        lineHeight: '1.45em',
        marginLeft: theme.spacing.unit*2,
        webkitFontSmoothing: 'antialiased'
    },
    appBar: {
      top: 'auto',
      bottom: 5,
      height: '10%'
    },
    toolbar: {
      alignItems: "center",
      justifyContent: "space-between"
    },
    textField: {
      fontSize: '12px',
      margin: theme.spacing.unit,
      minWidth: 120
    },
    formControl: {
      fontSize: '12px',
      margin: theme.spacing.unit,
      minWidth: 120
    },
    predictedDelay: {
        marginTop: '10px',
        position: 'relative',
        minWidth: 350,
        maxWidth: 350,
        textAlign: 'center',
        fontFamily: 'sans-serif',
        backgroundColor: 'rgb(225, 0, 80)'
    },
    predictedDelayText: {
        fontSize: '18px'
    },
    topControls: {
        borderBottom: '1px solid #ddd',
        height: '25%',
        boxShadow: '0 1px 4px rgba(0,0,0,0.08)',
        background: 'white',
        marginLeft: theme.spacing.unit*2,
        marginRight: theme.spacing.unit*2,
    },
    mainPart: {
        webkitJustifyContent: 'space-between',
        justifyContent: 'space-between',
        marginTop: '30px',
        marginBottom: '50px',
        paddingTop: '2px',
        position: 'relative',
        backgroundColor: '#f7f7f7'
    },
    card: {
        maxWidth: 200
    },
    paper: {
        backgroundColor: '#f7f7f7',
        padding: theme.spacing.unit * 2,
        height: '70%',
        marginLeft: theme.spacing.unit * 2,
        marginRight: theme.spacing.unit * 2,
    },
    buttons: {
        display: 'flex',
        justifyContent: 'flex-end',
    },
    rightIcon: {
        marginLeft: theme.spacing.unit,
    },
    button: {
        marginTop: theme.spacing.unit * 3,
        marginLeft: theme.spacing.unit,
    }
});

TopControls

import React, { Component, Fragment } from 'react';
import CssBaseline from '@material-ui/core/CssBaseline';
import Grid from '@material-ui/core/Grid';
import FormControl from '@material-ui/core/FormControl';
import Input from '@material-ui/core/Input';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import Select from '@material-ui/core/Select';
import TextField from '@material-ui/core/TextField';
import InputAdornment from '@material-ui/core/InputAdornment';

export default class extends Component {
    render() {
        return (
        <Fragment>
            <CssBaseline />

            <div className={this.props.styles.header}>
              <h1 className={this.props.styles.h1}>
                Prediction of departure delays for a single flight
              </h1>
            </div>

            <div className={this.props.styles.topControls}>
              <Grid container spacing={24}>
                <Grid item xs={2}>
                  <TextField
                      required
                      id="outlined-simple-start-adornment"
                      className={this.props.styles.textField}
                      onChange={(event) => this.props.handleChange("holdingTime", event)}
                      value={this.props.state.holdingTime}
                      margin="normal"
                      label="Holding time"
                      type="number"
                      InputProps={{
                          startAdornment: <InputAdornment position="start">(seconds)</InputAdornment>,
                      }}
                      onInput = {(e) =>{
                          e.target.value = Math.max(0, parseInt(e.target.value) ).toString().slice(0,12)
                      }}
                  />
                </Grid>
                <Grid item xs={2}>
                  <TextField
                      required
                      id="standard-number"
                      label="Additional ASMA 40"
                      onChange={(event) => this.props.handleChange("asma40", event)}
                      value={this.props.state.asma40}
                      type="number"
                      className={this.props.styles.textField}
                      margin="normal"
                      InputProps={{
                          startAdornment: <InputAdornment position="start">(seconds)</InputAdornment>,
                      }}
                  />
                </Grid>
                <Grid item xs={2}>
                  <TextField
                      required
                      id="standard-number"
                      label="Additional ASMA 60"
                      onChange={(event) => this.props.handleChange("asma60", event)}
                      value={this.props.state.asma60}
                      type="number"
                      className={this.props.styles.textField}
                      margin="normal"
                      InputProps={{
                          startAdornment: <InputAdornment position="start">(seconds)</InputAdornment>,
                      }}
                  />
                </Grid>
                <Grid item xs={2}>
                  <TextField
                    required
                    name="plannedDep"
                    id="datetime-local"
                    onChange={(event) => this.props.handleChange("plannedDep", event)}
                    value={this.props.state.plannedDep}
                    label="Scheduled departure"
                    type="datetime-local"
                    className={this.props.styles.textField}
                    margin="normal"
                    InputLabelProps={{
                      shrink: true,
                    }}
                  />
                </Grid>
                <Grid item xs={2}>
                  <TextField
                      required
                      id="standard-number"
                      label="Planned turnaround"
                      onChange={(event) => this.props.handleChange("schedTurnd", event)}
                      value={this.props.state.schedTurnd}
                      type="number"
                      className={this.props.styles.textField}
                      margin="normal"
                      InputProps={{
                          startAdornment: <InputAdornment position="start">(minutes)</InputAdornment>,
                      }}
                      onInput = {(e) =>{
                          e.target.value = Math.max(0, parseInt(e.target.value) ).toString().slice(0,12)
                      }}
                  />
                </Grid>
                <Grid item xs={2}>
                  <TextField
                      required
                      id="standard-number"
                      label="Taxi-In time"
                      onChange={(event) => this.props.handleChange("taxiInTime", event)}
                      value={this.props.state.taxiInTime}
                      type="number"
                      className={this.props.styles.textField}
                      margin="normal"
                      InputProps={{
                          startAdornment: <InputAdornment position="start">(seconds)</InputAdornment>,
                      }}
                      onInput = {(e) =>{
                          e.target.value = Math.max(0, parseInt(e.target.value) ).toString().slice(0,12)
                      }}
                  />
                </Grid>
              </Grid>
              <Grid container spacing={24}>
                <Grid item xs={2}>
                    <FormControl
                        required
                        className={this.props.styles.formControl}
                        margin="normal">
                        <InputLabel shrink htmlFor="wake-label-placeholder">
                                Wake
                        </InputLabel>
                        <Select
                          onChange={(event) => this.props.handleChange("wake", event)}
                          value={this.props.state.wake}
                          input={<Input name="wake" id="wake-label-placeholder" />}
                          displayEmpty
                          name="wake"
                        >
                          <MenuItem value={84.73}>Heavy</MenuItem>
                          <MenuItem value={14.78}>Medium</MenuItem>
                          <MenuItem value={0.49}>Light</MenuItem>
                        </Select>
                    </FormControl>
                </Grid>
                <Grid item xs={2}>
                  <TextField
                      required
                      id="standard-number"
                      label="Temperature"
                      onChange={(event) => this.props.handleChange("temperature", event)}
                      value={this.props.state.temperature}
                      type="number"
                      className={this.props.styles.textField}
                      margin="normal"
                      InputProps={{
                          startAdornment: <InputAdornment position="start">(Celsius)</InputAdornment>,
                      }}
                  />
                </Grid>
                <Grid item xs={2}>
                  <TextField
                      required
                      id="standard-number"
                      label="Visibility"
                      onChange={(event) => this.props.handleChange("visibility", event)}
                      value={this.props.state.visibility}
                      type="number"
                      className={this.props.styles.textField}
                      margin="normal"
                      InputProps={{
                          startAdornment: <InputAdornment position="start"></InputAdornment>,
                      }}
                      onInput = {(e) =>{
                          e.target.value = Math.max(0, parseInt(e.target.value) ).toString().slice(0,12)
                      }}
                  />
                </Grid>
                <Grid item xs={2}>
                  <TextField
                      required
                      id="standard-number"
                      label="Wind Intensity"
                      onChange={(event) => this.props.handleChange("windIntensity", event)}
                      value={this.state.windIntensity}
                      type="number"
                      className={this.props.styles.textField}
                      margin="normal"
                      InputProps={{
                          startAdornment: <InputAdornment position="start">(knots)</InputAdornment>,
                      }}
                      onInput = {(e) =>{
                          e.target.value = Math.max(0, parseInt(e.target.value) ).toString().slice(0,12)
                      }}
                  />
                </Grid>
                <Grid item xs={2}>
                  <TextField
                      required
                      id="standard-number"
                      label="Arrival delay"
                      onChange={(event) => this.props.handleChange("arrivalDelay", event)}
                      value={this.props.state.arrivalDelay}
                      type="number"
                      className={this.props.styles.textField}
                      margin="normal"
                      InputProps={{
                          startAdornment: <InputAdornment position="start">(minutes)</InputAdornment>,
                      }}
                      onInput = {(e) =>{
                          e.target.value = Math.max(0, parseInt(e.target.value) ).toString().slice(0,12)
                      }}
                  />
                </Grid>
                <Grid item xs={2}>
                  <TextField
                      required
                      id="standard-number"
                      label="Distance to target"
                      onChange={(event) => this.props.handleChange("distanceTarget", event)}
                      value={this.props.state.distanceTarget}
                      type="number"
                      className={this.props.styles.textField}
                      margin="normal"
                      InputProps={{
                          startAdornment: <InputAdornment position="start">(km)</InputAdornment>
                      }}
                      onInput = {(e) =>{
                          e.target.value = Math.max(0, parseInt(e.target.value) ).toString().slice(0,12)
                      }}
                  />
                </Grid>
              </Grid>
            </div>

        </Fragment>
      );
    }
}

有人知道问题出在哪里吗?

更新:

我也尝试过这个,但是它给了我同样的错误:

const TopControls = () => (
  ...
);

export default TopControls;

App.js

import React, { Component } from "react";
import SelectionPage from "../modes/SelectionPage";
import Main from "../modes/Main";
import Main2 from "../modes/Main2";

class App extends Component {
  state = {
    renderView: 0
  };

  clickBtn = e => {
    console.log(e.target.value);
    this.setState({
      renderView: +e.target.parentNode.value
    });
  };

  render() {
    switch (this.state.renderView) {
      case 1:
        return <Main />;
      case 2:
        return <Main2 />;
      default:
        return <SelectionPage clickBtn={this.clickBtn} />;
    }
  }
}

export default App;

2 个答案:

答案 0 :(得分:1)

似乎您无法将state直接传递给子组件。您可以通过两种主要方法来解决该问题。

第一个选项

您可以将这些值作为props传递。将state={this.state}更改为...this.state扩展运算符):

Main.js

render() {
    return <Fragment>
        <TopControls handleChange={this.handleChange} styles={styles} ...this.state/>
    </Fragment>
}

并直接从props中的TopControls.js获取这些值:

TopControls.js

render() {
    ...
    value={this.props.holdingTime}
    ...
}

第二个选项

只需使用其他道具传递状态即可:

Main.js

render() {
    return <Fragment>
        <TopControls myState={this.state} handleChange={this.handleChange} styles={styles} />
    </Fragment>
}

TopControls.js

render() {
    ...
    value={this.props.myState.holdingTime}
    ...
}

答案 1 :(得分:0)

return的{​​{1}}函数下使用render语句。

app.js

我对代码进行了一些修改,但这是相同的想法。