Rerender Problems in React Continued…
Avoiding Unwanted Referential Equality with State Changes
In a previous blog, which you can find here, I discussed some rerending issues that you might encounter if you have one piece of state in React depend on the change of another piece of state.
In this blog, we’ll look at another frequent rerending issue that involves changes in state that React does not consider worthwhile to force a component to rerender.
The issue at hand concerns referential equality and shallow comparison.
Follow Along / Test the Examples
Take the following example.
Check out the Repo
You can can fork and clone this repo to follow along, or follow the same example below.
Example
import { useState, useEffect } from 'react';
import ChildComponent from './components/ChildComponent';
const initialArray = [
{number: 1},
{number: 2},
{number: 3},
{number: 4},
{number: 5}
];const App = () => { const [myArray, setMyArray] = useState([]) useEffect(() => { setMyArray(initialArray) }, []) const reverseArray = () => {
const reversedArray = myArray.reverse()
setMyArray(reversedArray)
} return(
<>
<button onClick={reverseArray}>
Reverse Order
</button>
<ChildComponent arrayData={myArray} />
</>)
}export default App;
Here, we’ve set up a few things:
- We set up the piece of state called
myArray
and updated it after the component mounts (note that the second argument in theuseEffect
hook is “[]
”) with a value ofinitialArray
. TheinitialArray
value is—aptly named—an array, and is full of objects:initialArray = [ {number: 1}, {number: 2}, {number: 3}, {number: 4}, {number: 5} ]
- We created a button that will fire the function called
reverseArray
. - We defined the
reverseArray
function to take the state ofmyArray
, reverse it, and then set themyArray
value to that reversed order. So, when clicked the first time, it should reverse the order of the array to[ {number: 5}, {number: 4}, {number: 3}, {number: 2}, {number: 1} ]
. - We have passed the
myArray
piece of state down as a prop calledarrayData
in theChildComponent
.
Will the Child Component Rerender when we reverse the order of myArray
?
But why?
The change in our App’s state of myArray
is compared with its previous state when passed down to the ChildComponent
as a prop, but the comparison turns out to be too shallow in this case.
React and Referential Equality: Object.is
React uses the Object.is
when checking the objects in the array in this example. The comparison made is shallow, looking to see if the object admits of “referential equality” to the previous state’s object. (You can check out more on this issue here and here.)
So, React, to be efficient in the rendering and rerending of components, does not bother to rerender the ChildComponent
, treating the change in myArray
as not significant enough to count as a state change that would force a rerender.
This:
[ {number: 1}, {number: 2}, {number: 3}, {number: 4}, {number: 5} ]
looks too similar (using the Object.is
comparison of referential equality) to this:
[ {number: 5}, {number: 4}, {number: 3}, {number: 2}, {number: 1} ]
A Quick Fix
Did you notice anything fishy about how we reset state above (reproduced here):
const reverseArray = () => {
const reversedArray = myArray.reverse()
setMyArray(reversedArray)
}
Since JavaScript objects are pass-by-reference rather than pass-by-value, we actually mutated myArray
before running setMyArray
. This is demonstrated in the companion code:
- Open the application in the browser with
npm start
. - Open up the devtools console.
- Click the “Reverse Order” button.

COPY AND THEN MUTATE to Avoid Pass-By-Reference Side-Effects
As a good rule-of-thumb, it’s better to first copy an array before exerting any mutations on the data, so that you avoid any side-effects.
If we follow that rule-of-thumb here, using the spread operator like this:
const reverseArray = () => {
const reversedArray = [...myArray].reverse()
setMyArray(reversedArray)
}
then the value of reversedArray will be a new array. When we pass that into setMyArray
, React will notice the change.
You can demonstrate this, once again, in the companion code by commenting out l. 15 and commenting in l. 16. Now, when you hit the “Reverse Order” button you can see that the original array of myArray
is not being mutated with reversedArray
, and is non-identical with it:

By creating a copy and mutating, and then passing that new mutated copy into our function that changes state, React will recognize a state change and actually do what we intended from the beginning:
The new state passed as a prop to the ChildComponent will cause a rerender of the ChildComponent.
Conclusion
There’s really no “trick” at play here. Instead, we are following a programming principle that we should have noticed we were violating from the beginning:
Avoid side effects when working with JavaScript objects, such as arrays, by first creating a copy of that object.
The unintentional mutation of the original array, myArray
is a side effect. Following the principle of avoiding side effects such as this can help us avoid a problem of React ignoring a change in our state and props object due to referential equality.