In the example below I am using an ES6 Map as a state value in React:
class App extends React.Component {
constructor(props) {
super(props);
const results = new Map();
results["group1"] = [{ value: "..." }, { value: "..." }];
this.state = { results };
}
onUpdateClick(i) {
this.state.results["group1"][i].value = i;
this.setState({});
}
onResetClick(i) {
this.state.results["group1"][i].value = "...";
this.setState({});
}
render() {
const { results } = this.state;
return (
<div>
{results["group1"].map((r, i) => (
<div>
{r.value}
<button onClick={e => this.onUpdateClick(i)}>update</button>
<button onClick={e => this.onResetClick(i)}>reset</button>
</div>
))}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("container"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='container'></div>
When you click the button, I directly update the Map, in place and then call setState with no arguments. I do not make a clone/deep copy of the map. Based on my understanding of the React docs, this should not work and is explicitly warned against in the docs:
Never mutate this.state directly as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable
(https://reactjs.org/docs/react-component.html#state)
The docs also state that comparisons are shallow, so calling with an empty object should surely result in no merge and therefore no re-render?
Why does this example work?
(also I should note that I also reproduce this behaviour with React v16.9.0)
Edit: I also want to point out (since many answers refer to the fact that I am passing an empty object) that the component is re-rendered (and updated) if I call setState like so:
this.setState({ results: this.state.results })
which seems like it should not cause a re-render
From the documentation: setState
setState() will always lead to a re-render unless shouldComponentUpdate() returns false.
Which means that this.setState({}); leads to re-render regardless if you pass a change as an argument or not
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