SetState in React and How it behaves differently in Class and Functional Component

ยท

3 min read

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>
    );
  }
}

setState-record.gif

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>
  );
}

setState-func.gif

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

ย