question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Persisted state gets thrown away if any state is set in useEffect

See original GitHub issue

I’m having a strange bug where my persisted state is getting overridden.

I’m using Next.js, Zustand with the persist middleware, and localForage using async IndexedDB. I have default values set in my store, but when my app first runs I want to use some different default values in a useEffect depending on whether the user is using a mobile device or not.

According to my mental model of Zustand, what should happen is that the useEffect runs before or after the persisted state is loaded. If it runs before, the persisted state should get merged in with priority. If it runs after, the persisted state should be merged in with the properties in useEffect having priority. What I’d actually like to happen is for the useEffect to get run before, but it doesn’t matter for the purposes of this issue.

Instead, what seems to be happening is that all of my persisted properties get thrown away, and I get the default values along with the values I set in the useEffect. This doesn’t make sense to me, and it seems like a bug. My persisted properties should always stay persisted if I haven’t explicitly overridden them, which in this case I haven’t – all I’ve overridden are some other properties.

If I comment out the useEffect, then it works as you would expect: the persisted state stays persisted.

Hopefully this makes sense. If you’d like to take a look at my code to get a better idea of what I’m talking about, the store is here and the code that runs in the useEffect is here.

Edit: Minimal reproducible case: https://github.com/churichard/zustand-persist-bug

Click the button to increase the number of bears (which is stored in IndexedDB). Once you refresh the page, the bears resets to 0.

Comment out the useEffect to see it work fine and for the number of bears persist.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:15 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
AnatoleLucetcommented, Sep 20, 2021

I think what you said was slightly different. What I mean is for the initial state to actually be updated in the useEffect, but for that update to not be persisted into IndexedDB. Then, when IndexedDB is read later, it will override both the initial state and whatever happened in the useEffect.

Indeed I misunderstood 😄

This might be a better and more predictable default. And if someone doesn’t want their values to be overridden, they can still work around that with the merge option.

How does this hack fix, or not?

Should work. Though, if there’s no set() afterward, the data won’t be stored.

1reaction
dai-shicommented, Sep 19, 2021

Thanks for the reproduction! This should help. @AnatoleLucet Can you take a look?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Referencing outdated state in React useEffect hook
I tried to do the same with the useEffect hook, but it seems state is not correct in the return function of useEffect....
Read more >
Persistent State in React.js using useEffect hook - Dev Genius
If it exists, then we set the state. Note: localStorage takes takes in strings only and returns the same. Hence we used JSON.stringify()...
Read more >
Hooks API Reference - React
const [state, setState] = useState(initialState);. Returns a stateful value, and a function to update it. During the initial render, the returned state (...
Read more >
Understanding React's useEffect cleanup function
useEffect catches the fetch error in the catch block and then try to update the error state, which then throws an error. To...
Read more >
Atom Effects | Recoil
Atom effects are an API for managing side-effects and synchronizing or initializing Recoil atoms. They have a variety of useful applications such as...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found