Reputation: 5107
Currently, in my react app, I have a parent component which is housing two child components (TrendsComonent and BaselineComponent) and they load successfully. The parent component also has a dropdown component loaded.
What i want to do is set a default Component to load in the parent initially, but I want to map each child component to the dropdown options.
For instance, when the parent component is visited I would like to have TrendsComponent load initially as the default but have it tied to the trends dropdown option, as well as have the BaselineComponent mapped to the baseline option of the dropdown.
Basically, I just want to load components based on the dropdown option as opposed to all at once
TrendComponent.js
import React, { Component } from "react";
import Chart from "react-apexcharts";
import { StyleSheet, css } from 'aphrodite/no-important';
const styles = StyleSheet.create({
TrendsComponent: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
textAlign: 'center'
},
TrendsTitle: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems:'center'
}
});
class TrendsComponent extends Component {
render() {
return (
<div>
<div className={css(styles.TrendsTitle)}>
Net Calories
</div>
<div className={css(styles.TrendsComponent)}>
<div className={css(styles.TrendsComponent)}>
<div className="mixed-chart">
<Chart
/>
</div>
</div>
</div>
</div>
);
}
}
export default TrendsComponent;
BaselineComponent.js
import React, { Component } from "react";
import Chart from "react-apexcharts";
import { StyleSheet, css } from 'aphrodite/no-important';
const styles = StyleSheet.create({
TrendsComponent: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
textAlign: 'center'
},
TrendsTitle: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems:'center'
}
});
class BaselineComponent extends Component {
render() {
return (
<div>
<div className={css(styles.TrendsTitle)}>
Net Calories
</div>
<div >
<div >
<div className="mixed-chart">
<Chart
/>
</div>
</div>
</div>
</div>
);
}
}
export default BaselineComponent;
Then I have the parent component that currently holds that component as well as the dropdown
trendparent.js
import React, { Component } from "react";
import Chart from "react-apexcharts";
import { StyleSheet, css } from 'aphrodite/no-important';
import TrendsComponent from './Trendscomponent';
import BaselineComponent from './BaselineComponent';
import TrendDropdownComponent from './TrendDropdownComponent';
class trendparent extends Component {
render() {
return (
<div>
<div className={css(styles.TrendsTitle)}>
Net Calories
</div>
<div>
<div>
<div>
<TrendsComponent />
<BaselineComponent />
</div>
</div>
</div>
<div style={{height:50}}>
</div>
<div>
<TrendDropdownComponent />
</div>
</div>
);
}
}
export default trendparent;
dropdown.js
import React, { Component } from "react";
import { makeStyles } from '@material-ui/core/styles';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import FormHelperText from '@material-ui/core/FormHelperText';
import FormControl from '@material-ui/core/FormControl';
import Select from '@material-ui/core/Select';
const useStyles = makeStyles(theme => ({
formControl: {
margin: theme.spacing(1),
minWidth: 220,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
}));
export default function SimpleSelect() {
const classes = useStyles();
const [age, setAge] = React.useState('');
const inputLabel = React.useRef(null);
const handleChange = event => {
setAge(event.target.value);
};
return (
<div>
<FormControl className={classes.formControl}>
<InputLabel id="demo-simple-select-label">Calories</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={age}
onChange={handleChange}
>
<MenuItem value={10}>Trend</MenuItem>
<MenuItem value={20}>Baseline</MenuItem>
</Select>
</FormControl>
</div>
);
}
Upvotes: 0
Views: 414
Reputation: 4168
The question here is what you really mean by "load".
1) If what you mean by "load" means actually to only render a component that was statically imported (already declared in the beginning of the file), then all you have to do is set some default value on the state i.e. :
state = {
renderComponentX: false
}
And then on the dropdown change method change the state to true:
setState({"renderComponentX":true})
And inside render have a condition as :
{this.state.renderComponentX && <ComponentX />}
2) If on the other hand what you want is really to dynamically load components then it's a bit more complicated :
You need to create a component that Asynchronously loads other components. I normally create an array of randomKeys on the state of the component, at the constructor:
constructor(props) {
super(props);
// Dynamic Key Generation for dynamic view loading
let randomKeys = [];
while(randomKeys.length < 10){
let y = Math.random()*10000;
if(randomKeys.indexOf(y) === -1) randomKeys.push(y);
}
this.state = {
randomKeys
};
}
So that each of the new imported components will have a different Key.
In this case it's hardcoded to 0 but if you want to make this inside an iterator, you would have to create a variable to act as a counter to keep updating the index such as randomKeys[i]
where i
needs to grow from 0 to the length of components you want to import. Also you need to make sure to generate enough keys in the constructor; this one is only generating 10, because this was for manual import, not within an iterator.
<AsyncComponent key={this.state.randomKeys[0]} getComponent={() => import('../Login/Login.js')} />
and my AsyncComponent looks like this :
import React from 'react';
import PropTypes from 'prop-types';
export default class AsyncComponent extends React.Component {
state = {
AsyncModule: null,
};
componentDidMount() {
let that = this;
this.unmounted = false;
this.props.getComponent()
.then(module => {
console.log("AsyncComponent loaded module:",module);
return module.default;
})
.then(AsyncModule => {
if(that.unmounted!==true) {
that.setState({AsyncModule})
}
});
}
componentDidUpdate() {
}
componentWillUnmount() {
this.unmounted = true;
}
render() {
const {loader, ...childProps} = this.props;
const {AsyncModule} = this.state;
if(AsyncModule) {
return (<AsyncModule {...childProps} />)
}
if(loader) {
console.log('loader = ',loader);
return <div>Loading...</div>;
}
return null;
}
}
AsyncComponent.propTypes = {
getComponent: PropTypes.func,
loader: PropTypes.element
};
Upvotes: 1