How to solve Can't perform a React state update on an unmounted component in Next.js


When we update state on a React component, we want to make sure that the component is mounted first before altering its state
In this tutorial, we are going to:
- Reproduce the React Error Can't perform a React state update on an unmounted component in a Next.js project
- Present how to solve this error
Reproduce error
To reproduce this error, we are going to build two pages:
pages/test.js
import { useEffect, useState } from "react"
import Link from 'next/link'
import Router from 'next/router';
export default function Source() {
const [data, setData] = useState('')
useEffect(() => {
const callData = async () => {
const data = await fetch('https://jsonplaceholder.typicode.com/todos/10').then(data => data.json())
setData(data)
}
Router.onRouteChangeComplete = () => {
setData(data)
};
callData()
}, [])
return (data === '' ? <>loading ... </> : <div>{data.title}<hr/>
<Link href='/test1'><a>test1</a></Link></div>)
}
pages/test1.js
import Link from 'next/link'
const Destination = () => {
return (<div>Hello <hr />
<Link href='/test'><a>back </a></Link>
</div>)
}
export default Destination
Now when we click on the link to go to (test1.js), the error message is displayed as below
So the situation is that we have two components, one is called Source which has a link to component Destination
Source component is trying to update its state when component Destination is rendered
the update state happens when we call onRouteChangeComplete and we try to update data in the Source Component
Solve can't perform a react state update on an unmounted component
To solve this situation, we want to make sure that state updates which usually done using React hook useState are called only when the component is mounted
In our situation, we will fix this issue by cancelling all subscriptions in useEffect cleanup.
To do so, before updating any state we test if the useEffect has done and so cancel all state updated at that moment
Let's take a look
import { useEffect, useState } from "react"
import Link from 'next/link'
import Router from 'next/router';
export default function Source() {
const [data, setData] = useState('')
useEffect(() => {
let isSubscribed = true
const callData = async () => {
const data = await fetch('https://jsonplaceholder.typicode.com/todos/10').then(data => data.json())
setData(data)
}
Router.onRouteChangeComplete = () => {
isSubscribed? setData(data) :''
};
callData()
return () => (isSubscribed = false)
}, [])
return (data === '' ? <>loading ... </> : <div>{data.title}<hr/>
<Link href='/test1'><a>test1</a></Link></div>)
}
The setData is made only before useEffect has returned, and in that way we prevent performing state updates on an unmounted components
Now, test again and inspect the console when clicking on the link, you should see a clear console with no errors.
Conclusion
We have seen how to resolve can’t perform a React state update on an unmounted component in React based project like Next.js
I hope this will help you eliminate this warning