Everything you need to know about setState()

React is a JavaScript library for creating user interfaces. It has become one of the most popular libraries due to its simplicity and performance. While using React, it is very important to know about the state of React component and how to change it.

Annie Wang
Aug 15 · 7 min read

I found mutating the state can be very tricky and can possibly introduce a lot of problems. In this article, I am going to talk about the fundamental things you need to know about setState(). This includes some properties of setState() and detailed explanations about setState() in different lifecycles.

Let’s begin our journey and start with something easy.

What does setState() do?

To better understand what setState() does, let’s first take a look at what the state of a React component is.

The state allows React components to change their output over time in response to user actions, network responses, etc, without violating their rules. It can be initialized in the constructor of a React component and afterward, can be accessed via the React component’s class instance with the this object.

I know it might sound very complex if you are a beginner to React. So here is a simple example to help better explain it.

As you can see from this example, we initialize the state in the constructor and access it by using this.state.list in the render function.

Every time the state changes, the render method will run again and display the correct state in your browser. So in this case, when this.state.list changes, the UI will change correspondingly because of it being re-rendered.

When changing the state we cannot directly mutate the this.state. Instead, we should use setState(). One reason is, for a pure component, directly mutating state won’t trigger the component re-render, which could cause some odd bugs.

With setState() we can change the state without directly mutating it. This will lead to the re-rendering of the component due to the change of the state. However, we have to be extremely careful with it. Sometimes not using setState() properly will not only fail your goals but also generate some performance issues. So why is that? What kind of problems can we have?

Why do we need to be careful?

The most severe problem I have encountered so far by using setState() is crashing the website with an infinite loop. Since setState() triggers re-render, it is very easy to cause an infinite loop if it happens in the wrong lifecycle. We will take a deep look into lifecycles in the next section to see how it affects the performance.

Another thing we need to keep in mind is that setState() is asynchronous. Not being familiar with this property can bring us lots of trouble as well. It will not only introduce some errors but also cause some performance issues if we assume setState() is synchronous and expect the result right away.

Even though we put console.log() after setState(), it might not print out the latest state since the console log will execute before the state mutation. This is due to the asynchronism of setState() which cannot guarantee the mutation of state to act at the moment. In this case, React is doing its job and executes console.log() first and leaving setState() for the next event loop.

One way we can do this is to let React wait for the result of the new state and invoke the console.log() till then.

Which lifecycle is good for setState() and what are the differences?

Now let’s look at something fancier. We are going to go through what the React lifecycle is and why it is important for setState().

When developing in React, every component follows a cycle from when it is created and mounted on the DOM to when it is unmounted and destroyed. This can be broadly categorized into three parts: mounting, updating and un-mounting.

Here is a diagram demonstrating the main idea:

  • A component mounts when it is created and first inserted into the DOM. Like when the component is rendered for the first time.
  • Updating methods is when props change causing the component to be re-rendered. The updating lifecycle methods give you control over when and how this updating should take place.
  • When components are removed from the DOM, the un-mounting method will help us handle the un-mounting of components.

So when and how to put setState() at different lifecycles? Here is a brief summary I have for whether we can use setState() for each lifecycle.

Let’s start with something easy and more commonly used; the constructor and render methods.

In constructor, we should avoid using setState() because this is the only place we directly assign the initial state to this.state.

Also, we cannot directly put it in render() either since changing state each time triggers re-rendering which calls setState() again. This will result in an infinite loop.

However, we can use it in render method by using the setState() where we are assigning the props or attributes of other elements.

Below is an example that uses setState() in the render() method indirectly.

So what about other lifecycles? Let’s take a look at when these lifecycles will be invoked and how to use setState() at different lifecycles.

ComponentWillMount() is invoked just before the mounting occurs. Calling setState() usually won’t trigger an extra rendering because of the invoking order of this lifecycle, but it is usually not recommended to put setState() here due to the reason that initializing the state in constructor() can usually do a similar thing. However, if we want to implement functionality like , it is better to use componentDidMount() instead. Because if we need to subscribe to something, we usually need to unsubscribe from it in componentWillUnmount(). But componentWillMount() and componentWillUnmount() are not necessarily paired. When componentWillUnmount() is not being called due to server rendering or async rendering, it will result in memory leaks. However, componentDidMount() can solve it by guaranteeing componentWillUnmount() will later be called for clean up.

In the new version of React(v16.9.0), it is removed and componentDidmount() is recommended to use instead.

ComponentDidMount() is invoked immediately after a component is mounted. In componentDidMount(), using setState() won’t introduce any errors but it might cause performance issues because it will trigger an extra rendering and this will happen before the browser updates the screen. That is to say, the user won’t see the intermediate state but render() will be called twice in this case.

ComponentDidUpdate() is invoked immediately after updating occurs. This is a tricky place to put setState() because it is very easy to cause an infinite loop. It must be wrapped in a condition like below to avoid such a situation:

ComponentWillReceiveProps() is a method that is called before a component does anything with the new props. This method is called with the new props passed as an argument. To use setState() here it is better to check if the props change, otherwise it will change the state as long as new props value is passed and it can trigger unnecessary rendering.

ComponentWillUpdate() is a method that can be used to perform preparation before re-rendering occurs. You cannot call this.setState in this method.

Cat getting bored with React

Note that one side-effect when props change is componentWillUpdate() and componentWillReceiveProps() might get called multiple times for a single update while componentDidUpdate() is guaranteed to be invoked only once per update. Therefore, it is a good idea to move data update from componentWillReceiveProps() to componentDidUpdate() or getDerivedStateFromProps()(in React v16 upwards).

In React v16 upwards, componentWillReceiveProps() is removed and getDerivedStateFromProps() is introduced. We cannot use this.setState() here since it is a static method, instead, we directly return the updated state data. GetDerivedStateFromProps() is called both on initial mounting and on re-rendering of the component, so you can use it instead of creating the state based on props in the constructor. If you declare both getDerivedStateFromProps() and componentWillReceiveProps(), only getDerivedStateFromProps() will be called and a warning will be shown in the console.

It might sound really complex if you are a beginner to React, so it is highly recommended to check the table shown above if you are wondering if you can use setState() at a certain place and then read the corresponding explanation.

I hope you have more fun and easier development experience after reading this article.

Hootsuite Engineering

Hootsuite's Engineering Blog

Annie Wang

Written by

Co-op at P&C team at Hootsuite. A software engineer who loves critical thinking and likes to seek all the joyful and beautiful things in life. ╮(✧ఠ 。ఠ)╭

Hootsuite Engineering

Hootsuite's Engineering Blog

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade