While looking through the ReactJS code of a colleague, I noticed them "modifying the state directly". I also tried it out with this code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/babel">
class App extends React.Component {
constructor(props) {
super(props);
this.state = {"message":""};
}
textChange(evt) {
this.state.message = evt.currentTarget.value;
this.setState({});
}
render() {
return (
<div>
<p>{this.state.message}</p>
<input type="text" onChange={evt=>this.textChange(evt)} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
</script>
</body>
</html>
The method textChange(evt)
consistently and reliably updates the state. I read in a few blogs on the internet that we should not be modify the state directly...did I misunderstand something?
Also consider all these other ways of modifying states:
textChange1(evt) {
this.state.message = evt.currentTarget.value;
this.setState(this.state);
}
textChange2(evt) {
const state = this.state;
state.message = evt.currentTarget.value;
this.setState(state);
}
textChange3(evt) {
const state = this.state;
state.message = evt.currentTarget.value;
this.setState({});
}
textChange4(evt) {
this.setState({message:evt.currentTarget.value});
}
textChange5(evt) {
let message = evt.currentTarget.value;
this.setState({message});
}
Which of these is the idiomatic way to modify states in ReactJS?
You are correct in that we should never modify state directly (unless it's in the constructor). Doing so may work, but will lead to unintended side effects.
always create new objects and arrays when you call setState,
source: https://daveceddia.com/why-not-modify-react-state-directly/
Do Not Modify State Directly # <--- from react docs itself
source: https://reactjs.org/docs/state-and-lifecycle.html
In your example, the below 2 are the best/idiomatic ways to modify state. Note, when you use {}
you are initializing an object literal (i.e. creating a new object), which is what the below 2 methods are doing (but that of course in and of itself does not mean it's correct, as you can see with textChange3
).
// great
textChange4(evt) {
this.setState({message:evt.currentTarget.value});
}
// great
textChange5(evt) {
let message = evt.currentTarget.value; // note `let` should be `const` (style-wise) since you are not reassigning message, but otherwise this is fine!
this.setState({message});
}
Breaking down each method with comments
// not good
textChange1(evt) {
this.state.message = evt.currentTarget.value; // modifying original state object
this.setState(this.state);
}
// not good
textChange2(evt) {
const state = this.state; // this is the exact same as above,
// except you aliased this.state as state.
state.message = evt.currentTarget.value;
this.setState(state);
}
// not good
textChange3(evt) {
const state = this.state;
state.message = evt.currentTarget.value; // same problem as above of modifiying state directly
this.setState({}); // you might expect the state to be set to an empty object, but it's not
// in this case it's basically a no-op because state updates are merged. see https://reactjs.org/docs/state-and-lifecycle.html
}
// great
textChange4(evt) {
this.setState({message:evt.currentTarget.value});
}
// great
textChange5(evt) {
let message = evt.currentTarget.value; // note `let` should be `const` (style-wise) since you are not reassigning message, but otherwise this is fine!
this.setState({message});
}