Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

componentWillReceiveProps in child doesn't receive new props when setState() in parent

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?

like image 678
chemook78 Avatar asked Jan 19 '26 13:01

chemook78


1 Answers

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.

like image 191
Mayank Shukla Avatar answered Jan 21 '26 04:01

Mayank Shukla



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!