React 16 lets you decide whether state gets updated via .setState to prevent unnecessary DOM updates. Calling .setState with null no longer triggers an update in React 16.

We’ll explore how this works by refactoring a mocktail selection app that updates even if we choose the same mocktail twice.

The folder structure might look like this:
src |-> App.js |-> Mocktail.js |-> index.js |-> index.css |-> Spinner.js

Our application will render a selected mocktail. We can select/switch the mocktail by clicking on one of the buttons. When we do that, a new mocktail is loaded, and a new mocktail image is rendered after loading is complete.
The App component — the parent component — has a mocktail state and an updateMocktail method that handles updating the mocktail.
import React, { Component } from 'react';
import Mocktail from './Mocktail';
class App extends Component {
state = {
mocktail: ''
}
updateMocktail = mocktail => this.setState({ mocktail })
render() {
const mocktails = ['Cosmopolitan', 'Mojito', 'Blue Lagoon'];
return (
<React.Fragment>
<header>
<h1>Select Your Mocktail</h1>
<nav>
{
mocktails.map((mocktail) => {
return <button
key={mocktail}
value={mocktail}
type="button"
onClick={e => this.updateMocktail(e.target.value)}>{mocktail}</button>
})
}
</nav>
</header>
<main>
<Mocktail mocktail={this.state.mocktail} />
</main>
</React.Fragment>
);
}
}
export default App;
The updateMocktail method is called on the button element’s onClick event, and the mocktail state is being passed down to the child component Mocktail.
The Mocktail component has a loading state called isLoading that, when true, renders the Spinner component.
import React, { Component } from 'react';
import Spinner from './Spinner';
class Mocktail extends Component {
state = {
isLoading: false
}
componentWillReceiveProps() {
this.setState({ isLoading: true });
setTimeout(() =>
this.setState({
isLoading: false
}), 500);
}
render() {
if (this.state.isLoading) {
return <Spinner/>
}
return (
<React.Fragment>
<div className="mocktail-image">
<img src={`img/${this.props.mocktail.replace(/ +/g, "").toLowerCase()}.png`} alt={this.props.mocktail} />
</div>
</React.Fragment>
);
}
}
export default Mocktail;
setTimeout is called in the Mocktail component’s componentWillReceiveProps lifecycle method to set the loading state to true for 500 milliseconds.
This displays the loading spinner for half a second each time the Mocktail component’s props get updated with the new mocktail state, then it renders the mocktail image.
Now, the problem with this is that the mocktail state gets updated and triggers a re-render of the Mocktail component no matter what — even if the state doesn’t actually change.
For example, each time I click the Mojito button, we see the app unnecessarily re-render the Mojito image. React 16 provides state performance improvements that enable us to prevent an update from being triggered by returning null in setState if the state’s new value is the same as its existing value.

Here are the steps we will follow to prevent unnecessary re-render:
nullnull will not update state and trigger a component re-renderSo first, in the updateMocktail method of the App component, we’ll create a constant called newMocktail and assign it the value being passed in for the mocktail.
updateMocktail = mocktail => {
const newMocktail = mocktail;
this.setState({
mocktail
})
}
Since we’re going to be checking and setting state based on a previous state, rather than passing setState and object, we’ll pass it a function that takes the previous state as a parameter. Then we’ll check if the new value of the mocktail state is the same as the existing one.
If the values are the same, setState will return null. Otherwise, if the values are different, setState will return the updated mocktail state, which will trigger a re-render of the Mocktail component with the new state.
updateMocktail = mocktail => {
const newMocktail = mocktail;
this.setState(state => {
if (state.mocktail === newMocktail) {
return null;
} else {
return { mocktail };
}
})
}

Now, clicking a button still loads its respective mocktail image. However, if we click the button again for the same mocktail, React does not re-render the Mocktail component; because setState is returning null, there is no state change to trigger an update.
I’ve highlighted the updates in React DevTools in the two gifs below:


Note: I have used a dark theme here so it is easier to observe the update in React DOM using the React DevTools highlight updates feature.
Now we have covered returning null from setState in React 16. I’ve added the full code for the mocktail selection app in the CodeSandbox below for you to play around with and fork.
Preventing unnecessary state updates and re-renders with null can make our application perform faster, and the whole point of making application perform faster is to improve our app’s user experience.
Users don’t stumble on a product for no reason. How users feel about a product directly reflects their views of the company and its products, so we need to make sure we build an experience around our users’ expectations in a way that feels natural and intuitive.
I hope you’ve found this post informative and helpful. I would love to hear your feedback!
Thank you for reading!
Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, not
server-side
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
// Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
We explore and compare five of the most prominent JavaScript mapping APIs: Leaflet, Mapbox GL JS, OpenLayers, ArcGIS, and the Google Maps API.
Combine NeonDB, Prisma ORM, and Apollo Server within a serverless architecture to achieve a fully functional and scalable GraphQL API.
Interaction to Next Paint was added to Google’s Core Web Vitals to provide a more comprehensive assessment of website interactivity.
Explore Docusaurus and Starlight for building and customizing documentation websites, comparing their features such as sidebars, light/dark mode, and tabs.
3 Replies to "Returning null from setState in React 16"
Point of clarification for someone relatively new to React: am I correct to say that it is not necessary to return null with setstate in the way described in this article when the [unchanging] state value(s) are members of a mapped list (where each member in the list has been assigned a unique key)? Or restated, is it the case that a mapped list, where each element in the list is assigned a unique key, only updates those elements where a state change has occurred, and so the technique explained by this article would not be necessary for unchanging elements of a mapped list even when other elements in the list undergo state changes?
Great article, by the way. Everything makes sense. My question is mostly to make sure I have everything straight when it comes to state updates.
Why not just completely skip the setState call if new === current mocktail?
Yeah