How to restore persisted state on page refresh #1569
-
I'm kind of a noob in state management.... I want to know how to restore the state from indexeddb on page refresh. The state is being set as I want but when I refresh the page it is lost and back to initial. I have this basic setup // auth.store.ts
import { create } from 'zustand'
import { createJSONStorage, persist } from 'zustand/middleware'
import storage from './storage';
interface AuthState {
authUser: Object,
}
interface Actions {
setAuthUser: (user: any) => void
}
export const useAuthStore = create<AuthState & Actions>()(
persist((set, get) => ({
authUser: {},
setAuthUser: (user: any) => set(() => ({ authUser: user }))
}),
{
name: "authstorage",
storage: createJSONStorage(() => storage as any)
}),
) and then in my component after login I have this import { useAuthStore } from "@/stores/auth.store";
const Home = () => {
const user = useAuthStore.getState().authUser
return (<>
<div>
<h3>{JSON.stringify(user)}</h3>
</div>
</>)
}
Home.layout = 'publicLayout';
export default Home; Just after login when I come to the page I have userData but when I refresh it is back to {}. It is stated though that zustand handles persisted state restoring. What am I doing wrong here ? Thanks for any hint. I'm using next.js and localForage as custom storage for zustand persist |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 2 replies
-
Hey I figured out my issue has to do with hydration, since I'm using an async storage. Looked up in the docs and found a solution to my problem. // use-hydration.ts
import { useEffect, useState } from 'react';
import { StoreApi, UseBoundStore, } from 'zustand'
import { StorePersist, Write } from 'zustand/middleware';
export const useHydration = (boundStore: UseBoundStore<Write<StoreApi<any>, StorePersist<any, unknown>>>) => {
const [hydrated, setHydrated] = useState(boundStore.persist.hasHydrated);
useEffect(() => {
const unsubHydrate = boundStore.persist.onHydrate(() => setHydrated(false))
const unsubFinishHydration = boundStore.persist.onFinishHydration(() => setHydrated(true))
setHydrated(boundStore.persist.hasHydrated())
return () => {
unsubHydrate()
unsubFinishHydration()
}
}, []);
return hydrated;
} And then in my component I have the following:
Now it's working as I expect. |
Beta Was this translation helpful? Give feedback.
-
I'd suggest though that the types such as Write, StoreApi, StorePersist and WithDevtools should be exported from the package in future version of zustand. Thanks for this nice package. |
Beta Was this translation helpful? Give feedback.
-
There is a new solution, when I used it I didn't need any extra package or hooks; the solution is In my case code looks like this; import { UserPayload } from 'src/swagger/api/base';
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
interface CurrentUserStore {
user: UserPayload;
setUser: (user: UserPayload) => void;
clearUser: () => void;
}
export const useCurrentUserStore = create<CurrentUserStore>()(
persist(
set => ({
user: {} as UserPayload,
setUser: user => set({ user }),
clearUser: () => set({ user: {} as UserPayload }),
}),
{
name: 'currentUser',
storage: createJSONStorage(() => sessionStorage),
// merge works perfect
merge: (persistedState, currentState) => ({ ...currentState, ...(persistedState as CurrentUserStore) }),
},
),
); |
Beta Was this translation helpful? Give feedback.
-
Anyone having this issue on NextJS 15? I am :/ Edit: I had to add a "merged" boolean property to the app store and update it's state in the "merge" function like in the example above (thanks for that). And I only try to fetch data after the merge is complete, if needed. |
Beta Was this translation helpful? Give feedback.
Hey I figured out my issue has to do with hydration, since I'm using an async storage. Looked up in the docs and found a solution to my problem.
Here is my solution