SetState in React and How it behaves differently in Class and Functional Component
The setState is a method or function in react that is used to update the state. If you know about getters and setters, it can be said to behave as the setter for the state in react. However, not many react developers would know that setState behaves differently in class-based components compared to its counterpart, functional components.
After reading this article, you would have been familiar with what the difference in behavior is: the subtle difference setState has in class and functional components. With no further ado, let's get down to business.
setState in Class Component
setState in a class component does shallow merge out of the box. That is if you do not spread the state and object returned from setState, but instead only returned an object as an update, the setState would make the shallow merge for you (kind of like doing the spreading on your behalf), now that is magic ๐งจ.
If the paragraph above seems unclear, do not worry ๐. Read the code below and I am sure it will get clearer.
const obj = {
names: ["kelvin", "sekx"],
age: 23
}
shallowMerge({age: 32}) // ๐
/** returns
{
names: ["kelvin", "sekx"],
age: 32
}
*/
function shallowMerge(update){
return Object.assign(obj, update)
}
Now, remember what I mentioned about merging (You can quickly take another read of the previous paragraph I will wait). Our shallowMerge function took an object with an updated property, age, of the obj
object, and returns a new object where other properties like names are merged out of the box.
This is what react does for us when this.setState is used.
It is time to put it into action in a real react code.
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
city: ["Ibadan", "Ikeja", "Jalingo", "Jos"],
countries: "Nigeria"
};
this.handleClick = this.handleClick.bind(this)
}
// ๐ WE'VE UPDATED THE STATE WITH A NEW OBJECT
handleClick() {
this.setState({ countries: "USA" }); //๐ I didn't spread the previous state
}
render() {
return (
<div>
<button onClick={this.handleClick}>Click me to change country</button>
<pre>{JSON.stringify(this.state, null, 2)}</pre>
</div>
);
}
}
Hollop that is crazy ๐. But that is the catch also, setState does not behave as such in a functional component.
export default function App() {
const [state, setState] = React.useState({
city: ["Ibadan", "Ikeja", "Jalingo", "Jos"],
countries: "Nigeria"
});
const handleClick = function () {
setState({ countries: "USA" });
};
return (
<div>
<button onClick={handleClick}>Click me to change country</button>
<pre>{JSON.stringify(state, null, 2)}</pre>
</div>
);
}
Can I override an object with this.setState?
No, you can't. It is almost impossible to make this.setState behave like setState does in functional components.
Conclusion
Wow, I am happy you learned something. Knowing about these little features can be a significant game changer to writing a better react code, and I am happy this helped.
Please if you find a typo or something I can write better in this article, kindly reach out to me on Twitter at utdkelvin. Happy hacking!!!