14

I have a functional component where I get a value from my localStorage and use that value to set a value in a state:

localforage.getItem<string>('sortType').then((value) => {
  setSortType(value)
})

const [sortType, setSortType] = useState('release_date');

When I run the component I get a log:

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

I've read that this happens because I'm using a async method localforage.getItem on a state. But I haven't found a solution that would work in a functional component.

Damien Sawyer
  • 5,323
  • 3
  • 44
  • 56
Peter Boomsma
  • 8,851
  • 16
  • 93
  • 185
  • Could it be a case of defining the states before you set the state? – bishal Aug 02 '20 at 07:47
  • 1
    Does this answer your question? [Can't perform a React state update on an unmounted component](https://stackoverflow.com/questions/53949393/cant-perform-a-react-state-update-on-an-unmounted-component) – ford04 Aug 02 '20 at 09:53

2 Answers2

15

You are setting the state after the promise resolves, which can cause this code to run after the component has unmounted.

To resolve this, you can check if the component is still mounted before setting the state:

const isMountedRef = useRef(true)
useEffect(() => () => { isMountedRef.current = false }, [])

Since the dependency array is empty the effect is called when the component mounts, and the callback is executed when it dismounts

// somewhere in your code later
localforage.getItem<string>('sortType').then((value) => {
  if (isMountedRef.current) {
      setSortType(value)
  }
})
thedude
  • 9,388
  • 1
  • 29
  • 30
  • Could you explain when a component dismounts? In other words when is the `useEffect` hook called, I see it's after I change something in the component. – Peter Boomsma Aug 02 '20 at 08:07
  • I've updated my answer with an explanation, hope it helps – thedude Aug 02 '20 at 08:18
  • When you can call ```localforage.getItem``` once in useEffect, So, why we need to check the mounted status? – Ali Torki Aug 02 '20 at 08:35
  • Because the `then` callback might still be executed *after* the components was unmounted. – thedude Aug 02 '20 at 08:41
  • 1
    https://stackoverflow.com/questions/53949393/cant-perform-a-react-state-update-on-an-unmounted-component?noredirect=1&lq=1#comment115991638_60907638 was helpful for me. +1 here too. – Ryan Jan 06 '21 at 23:31
1

Try to run the sortType from localStorage once by using React.useEffect as below:

const [sortType, setSortType] = useState('release_date');

React.useEffect(() => {
  localforage.getItem<string>('sortType').then((value) => {
    setSortType(value)
  })
}, []);
Ali Torki
  • 1,929
  • 16
  • 26