Я пытаюсь лучше структурировать свой исходный код.
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)
в приложении (в src / index.js: 5)
react-dom.development.js: 57 Uncaught Ошибка: недопустимый тип элемента:
ожидается строка (для встроенных компонентов) или класс / функция (для
составные компоненты) но получил: объект. Вы, вероятно, забыли экспортировать
ваш компонент из файла, в котором он определен, или вы могли смешать
up по умолчанию и именованный импорт.
Проверьте метод рендеринга _default
.
в инварианте (response-dom.development.js: 57)
в createFiberFromTypeAndProps (react-dom.development.js: 10531)
в createFiberFromElement (react-dom.development.js: 10551)
в createChild (реагировать-dom.development.js: 13811)
at reconcileChildrenArray (реагировать на dom.development.js: 14080)
at reccileChildFibers (response-dom.development.js: 14430)
в примирение детей (реагировать-dom.development.js: 14817)
at finishClassComponent (response-dom.development.js: 15161)
в updateClassComponent (react-dom.development.js: 15096)
на beginWork (реагировать-dom.development.js: 15980)
at executeUnitOfWork (Reaction-dom.development.js: 19102)
на рабочем месте (реагировать-dom.development.js: 19143)
в HTMLUnknownElement.callCallback (react-dom.development.js: 147)
в Object.invokeGuardedCallbackDev (Reaction-dom.development.js: 196)
at invokeGuardedCallback (react-dom.development.js: 250)
в replayUnitOfWork (response-dom.development.js: 18350)
в renderRoot (реагировать на dom.development.js: 19261)
at executeWorkOnRoot (реагировать на dom.development.js: 20165)
на PerforWork (реагировать на dom.development.js: 20075)
на executeSyncWork (реагировать на dom.development.js: 20049)
в интерактивном обновлении $ 1 (react-dom.development.js: 20337)
в интерактивном обновлении (response-dom.development.js: 2267)
at dispatchInteractiveEvent (react-dom.development.js: 5083) invariant @ реагировать-dom.development.js: 57 createFiberFromTypeAndProps @
response-dom.development.js: 10531 createFiberFromElement @
response-dom.development.js: 10551 createChild @
response-dom.development.js: 13811 reconcileChildrenArray @
response-dom.development.js: 14080 reconcileChildFibers @
response-dom.development.js: 14430 примирить детей @
response-dom.development.js: 14817 finishClassComponent @
response-dom.development.js: 15161 updateClassComponent @
response-dom.development.js: 15096 beginWork @
response-dom.development.js: 15980 executeUnitOfWork @
response-dom.development.js: 19102 workLoop @
response-dom.development.js: 19143 callCallback @
response-dom.development.js: 147 invokeGuardedCallbackDev @
response-dom.development.js: 196 invokeGuardedCallback @
response-dom.development.js: 250 replayUnitOfWork @
response-dom.development.js: 18350 renderRoot @
response-dom.development.js: 19261 executeWorkOnRoot @
response-dom.development.js: 20165 executeWork @
response-dom.development.js: 20075 executeSyncWork @
response-dom.development.js: 20049 интерактивных обновлений $ 1 @
response-dom.development.js: 20337 interactiveUpdates @
react-dom.development.js: 2267 dispatchInteractiveEvent @
response-dom.development.js: 5083 index.js: 1446 Произошла вышеуказанная ошибка
в компоненте <_default>:в _default (в App.js: 21)
в приложении (в 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>
);
}
}
Кто-нибудь знает, где проблема?
UPDATE:
Я тоже пробовал это, но выдает ту же ошибку:
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;