Reputation: 1663
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.
Upvotes: 9
Views: 4677
Reputation: 6693
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.
Upvotes: 13