Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nextProps always identical to this.props in componentWillReceiveProps, even when the props have changed

I have a component in my React app that renders a total value for the user. When that value goes up, I want to play a noise. I figured that within the component that displays the total would be a good place to play that noise from.

So I added a componentWillReceiveProps method to the component, and in it, I calculate two totals: total is calculated from this.props and nextTotal is calculated from nextProps.

To my surprise, even when the values change, and the totals change, nextTotal and total are always the same. So the conditional that I want firing when the total goes up never happens.

I wrote up a simple, single-component example. JSfiddle.

var Hello = React.createClass({
  componentWillReceiveProps: function(nextProps) {
    var total = 0;
    this.props.vals.forEach(val => total+= val);

    var nextTotal = 0;
    nextProps.vals.forEach(val => nextTotal+= val);

        console.log(total, nextTotal)

    if (nextTotal > total) {
            //never runs
            console.log('moving up');
        }
  },
  render: function() {
    var total = 0;
    vals.forEach(val => total+= val)
    return (
        <div>{total}</div>
    )
  }
});

var vals = [1, 21, 452, 123];

setInterval(renderReact, 1000)

function renderReact() {
    vals.push(10);
  ReactDOM.render(
    <Hello
      vals={vals}
    />,
    document.getElementById('container')
  );
}

As you can see, every second it adds 10 to the vals array, which means the total moves up by 1. But if you open the console, you can see that total and nextTotal are always the same, and moving up never gets logged.

I'm clearly misunderstanding something, and if anyone could explain what my misunderstanding is, and how I should achieve what I'm going for, that would be fantastic.

like image 526
fnsjdnfksjdb Avatar asked Apr 26 '16 19:04

fnsjdnfksjdb


People also ask

Is componentWillReceiveProps deprecated?

With the release of React 16.3, some new lifecycle methods have been introduced, and release of React 17 will deprecate some lifecycle method. getDerivedStateFromProps is one of those newly introduced lifecycle method replacing componentWillReceiveProps , which has now become UNSAFE_componentWillReceiveProps .

Where does props get updated in lifecycle?

ReactJS – componentWillReceiveProps() Method This method is used during the updating phase of the React lifecycle. This function is generally called if the props passed to the component change. It is used to update the state in response with the new received props.

When should I use componentWillReceiveProps?

The componentWillReceiveProps() is invoked before our mounted React component receives new props. It is called during the updating phase of the React Life-cycle. It is used to update the state in response to some changes in our props.

What is shouldComponentUpdate?

The shouldComponentUpdate is a lifecycle method in React. This method makes the component to re-render only when there is a change in state or props of a component and that change will affect the output.


1 Answers

As noted in the comments (by @PitaJ), your problem is that you're passing in an array the first time, and then ALTERING the array - rather than calling with a new property. You've reached into the object your component is holding a reference to as its existing property and changed the contents of it.

In your fiddle, try this:

function renderReact() {
    vals.push(10);
  ReactDOM.render(
    <Hello
      vals={vals.concat([])}
    />,
    document.getElementById('container')
  );
}

Passing a copy of the array in as your prop each time, you'll see they differ appropriately.

This is actually a non-trivial source of error in using react, and can crop up even when using redux with it if reducers aren't carefully written. Using immutable data structures is one way to avoid it.

like image 164
S McCrohan Avatar answered Oct 12 '22 11:10

S McCrohan