One does not simply “setState”

Amitosh Swain Mahapatra
3 min readAug 11, 2019

--

If you have used ReactJS I bet you are familiar with “setState”. What if I told you, you cannot simply reliably set state using “setState”. Forgive the puns!

When I was learning React, upon my first encounter with setState, I thought “It’s like changing the value of a variable. This does one thing, changes the state, right?” Little did I know that there is deep sorcery behind the simple function.

The situation

A while ago when developing an SPA for a client, I encountered (again a simple looking) requirement where I had to update several counter on receiving some events from the server over WebSockets and another that directly corresponded to the number of clicks made on a button. Think of it like a dynamically updating counter on a dashboard.

A little recap…

A React component is like a function of externally supplied props and some internal state which returns HTML that is rendered in the browser. State and props affect how the component renders and behaves. The state is local to the component and can only be initialized and updated within the component.

State can be updated in response to events such as UI interaction, server responses or prop changes. React provides a method called setState for this purpose. It enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state.

And based on this knowledge, my simple first implementation was:

class Counter extends React.Component {
state = {
event: 0,
clicks: 0
}
componentDidMount() {
monitoring(...).subscribe(() => this.setState({
event: this.state.value + 1
}));
}
handleButtonClick = e => this.setState({
clicks: this.state.clicks + 1
})
render() {
// ...
}
}

This works to some extent, lets say when the events are coming at a slow and steady pace. But when there is a burst of activity, all hell breaks loose.

Why?

Because setState is asynchronous. React can batch state updates and defer rendering till it seems fit for performance reasons. So when setState is applied, the value of the current state is always stale, which resulted in missing click and event counts.

Introducing the setState with callbacks

setState accepts a callback which computes state as a function of the current state, like this:

this.setState((currentState) => ({
click: currentState.click + 1
});

This guarantees that the value set by setState is always up to date.

Reusable setState

There is another interesting side-effect of this pattern. setState is now a function that can be shared and composed between different components which leads to better code re-usability.

React has many such well kept “secrets”. Do you know any of such interesting APIs that are not widely known? Let me know in the comments!

--

--

Amitosh Swain Mahapatra
Amitosh Swain Mahapatra

Written by Amitosh Swain Mahapatra

Computer Whisperer. Open-source contributor. Find me at https://amitosh.in/

Responses (1)