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.
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 .
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.
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.
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.
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.
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