I have a parent component in React called "App" that renders a "Calories" child component with a HighCharts implementation.
What I expect is according to the React lifecycle, parent renders child component and then will call componentDidMount(). I then use a fetch to get data async and once done it setState's the parent with a user object. Then it would re-render the child component with user={this.state.user} and it will be available in the child component. But when i log this.props in the child's componentWillReceiveProps the user object doesn't exist. So this line in child component logs "undefined":
componentWillReceiveProps: function(){
const series = this.props.series;
console.log("component Will Receive Props")
console.log(this.props);
}
Here is my full code:
const App = React.createClass({
//parent component to render all elements and hold state
getInitialState(){
return{
user: {},
series: [{
name: 'Jane',
data: [1, 0, 4]
}, {
name: 'John',
data: [5, 7, 3]
}]
};
},
componentDidMount: function(){
const fb_id = location.pathname.replace("/users/","");
fetch("https://someurl.com/usersdata/" + fb_id)
.then(rsp => rsp.json())
.then(json => {
if(json.error && json.error.message){
throw new Error(json.error.message);
}
this.setState({user:json}, ()=>{
console.log("state updated");
console.log(this.state);
});
});
},
render: function(){
return (
<div className="container">
<div clasNames="row">
<div className="col-xs-12">
{/*Send this.state.user data from fetch to child component*/}
<Calories series={this.state.series} user={this.state.user}/>
</div>
</div>
<div className="row">
<div className="col-xs-7">
<div className="bottom-left" id="weight-line-chart">
<Weight/>
</div>
</div>
<div className="col-xs-5">
<div className="bottom-right" id="avg-calories-pie-chart">
<AverageCal/>
</div>
</div>
</div>
</div>
);
}
});
//Calories Line chart
const Calories = React.createClass({
componentDidMount: function(){
const series = this.props.series;
console.log("component Did Mount");
console.log(this.props);
$(function () {
const myChart = Highcharts.chart('calories-line-chart', {
chart: {
type: 'line'
},
title: {
text: 'Your Calories Over Time'
},
xAxis: {
categories: ['Apples', 'Bananas', 'Oranges']
},
yAxis: {
title: {
text: 'Fruit eaten'
}
},
series: series
});
});
},
componentWillReceiveProps: function(){
const series = this.props.series;
console.log("component Will Receive Props")
console.log(this.props);
$(function () {
const myChart = Highcharts.chart('calories-line-chart', {
chart: {
type: 'line'
},
title: {
text: 'Your Calories Over Time'
},
xAxis: {
categories: ['Apples', 'Bananas', 'Oranges']
},
yAxis: {
title: {
text: 'Fruit eaten'
}
},
series: series
});
});
},
render:function(){
return(
<div>
<h3>Calories Intake</h3>
<div className="top" id="calories-line-chart">
</div>
</div>
);
}
});
Anybody can help me what I am doing wrong?
componentWillReceiveProps get called when props values of child (inside parent component) will get updated, you need to receive the new values as a parameter in this lifecycle method, like this:
componentWillReceiveProps: function(newProps){ //here
console.log("component Will Receive Props", newProps); //it will log the new values
...
}
this.props inside componentWillReceiveProps will have the previous values and it will get updated after this lifecycle method. If you do console.log(this.props) inside render, you will see the updated values.
Why we need to receive the new values as parameter?
I think reason is (not sure), this method get called whenever we do setState in parent component, irrespective of whether that is related to child component or not, so we need to put some logic before doing any task in child (new props and old props are same or not), because of that this.props will have the old values inside this method.
Check the DOC for more details on componentWillReceiveProps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With