diff --git a/examples/with-zustand/README.md b/examples/with-zustand/README.md
index fcfa14abbf05a..83aff9f87c174 100644
--- a/examples/with-zustand/README.md
+++ b/examples/with-zustand/README.md
@@ -10,7 +10,7 @@ To illustrate SSG and SSR, go to `/ssg` and `/ssr`, those pages are using Next.j
The trick here for supporting universal Zustand is to separate the cases for the client and the server. When we are on the server we want to create a new store every time, otherwise different users data will be mixed up. If we are in the client we want to use always the same store. That's what we accomplish on `store.js`.
-All components have access to the Zustand store using `useStore`.
+All components have access to the Zustand store using `useStore()` returned from zustand's `createContext()` function.
On the server side every request initializes a new store, because otherwise different user data can be mixed up. On the client side the same store is used, even between page changes.
diff --git a/examples/with-zustand/components/clock.js b/examples/with-zustand/components/clock.js
index 4e44981951cc5..04f53bd18a1ae 100644
--- a/examples/with-zustand/components/clock.js
+++ b/examples/with-zustand/components/clock.js
@@ -1,4 +1,4 @@
-import { useStore } from '../lib/zustandProvider'
+import { useStore } from '../lib/store'
import shallow from 'zustand/shallow'
const useClock = () => {
diff --git a/examples/with-zustand/components/counter.js b/examples/with-zustand/components/counter.js
index 7514be0e30277..338da5563cd93 100644
--- a/examples/with-zustand/components/counter.js
+++ b/examples/with-zustand/components/counter.js
@@ -1,4 +1,4 @@
-import { useStore } from '../lib/zustandProvider'
+import { useStore } from '../lib/store'
import shallow from 'zustand/shallow'
const useCounter = () => {
const { count, increment, decrement, reset } = useStore(
diff --git a/examples/with-zustand/components/page.js b/examples/with-zustand/components/page.js
index 9bfec37916441..1f669f1d50b43 100644
--- a/examples/with-zustand/components/page.js
+++ b/examples/with-zustand/components/page.js
@@ -2,7 +2,7 @@ import useInterval from '../lib/useInterval'
import Clock from './clock'
import Counter from './counter'
import Nav from './nav'
-import { useStore } from '../lib/zustandProvider'
+import { useStore } from '../lib/store'
export default function Page() {
const { tick } = useStore()
diff --git a/examples/with-zustand/lib/store.js b/examples/with-zustand/lib/store.js
index 3a064fcabefef..49bc825adc535 100644
--- a/examples/with-zustand/lib/store.js
+++ b/examples/with-zustand/lib/store.js
@@ -1,5 +1,6 @@
-import { useMemo } from 'react'
+import { useLayoutEffect } from 'react'
import create from 'zustand'
+import createContext from 'zustand/context'
let store
@@ -9,7 +10,9 @@ const initialState = {
count: 0,
}
-function initStore(preloadedState = initialState) {
+export const { Provider, useStore } = createContext(initialState)
+
+export const initializeStore = (preloadedState = {}) => {
return create((set, get) => ({
...initialState,
...preloadedState,
@@ -37,31 +40,30 @@ function initStore(preloadedState = initialState) {
}))
}
-export const initializeStore = (preloadedState) => {
- let _store = store ?? initStore(preloadedState)
+export function useHydrate(initialState) {
+ let _store = store ?? initializeStore(initialState)
+
+ // For SSR & SSG, always use a new store.
+ if (typeof window !== 'undefined') {
+ // For CSR, always re-use same store.
+ if (!store) {
+ store = _store
+ }
- // After navigating to a page with an initial Zustand state, merge that state
- // with the current state in the store, and create a new store
- if (preloadedState && store) {
- _store = initStore({
- ...store.getState(),
- ...preloadedState,
- })
- // Reset the current store
- store = undefined
+ // And if initialState changes, then merge states in the next render cycle.
+ //
+ // eslint complaining "React Hooks must be called in the exact same order in every component render"
+ // is ignorable as this code runs in the same order in a given environment (CSR/SSR/SSG)
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ useLayoutEffect(() => {
+ if (initialState && store) {
+ store.setState({
+ ...store.getState(),
+ ...initialState,
+ })
+ }
+ }, [initialState])
}
- // For SSG and SSR always create a new store
- if (typeof window === 'undefined') return _store
- // Create the store once in the client
- if (!store) store = _store
-
return _store
}
-
-export function useHydrate(initialState) {
- const state =
- typeof initialState === 'string' ? JSON.parse(initialState) : initialState
- const store = useMemo(() => initializeStore(state), [state])
- return store
-}
diff --git a/examples/with-zustand/lib/zustandProvider.js b/examples/with-zustand/lib/zustandProvider.js
deleted file mode 100644
index d9fa9de31f133..0000000000000
--- a/examples/with-zustand/lib/zustandProvider.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import { createContext, useContext } from 'react'
-
-export const StoreContext = createContext(null)
-
-export const StoreProvider = ({ children, store }) => {
- return {children}
-}
-
-export const useStore = (selector, eqFn) => {
- const store = useContext(StoreContext)
- const values = store(selector, eqFn)
-
- return values
-}
diff --git a/examples/with-zustand/package.json b/examples/with-zustand/package.json
index 43ed3b892251b..1440d8d38a974 100644
--- a/examples/with-zustand/package.json
+++ b/examples/with-zustand/package.json
@@ -10,7 +10,7 @@
"next": "latest",
"react": "^16.9.0",
"react-dom": "^16.9.0",
- "zustand": "3.1.3"
+ "zustand": "3.5.0"
},
"license": "MIT"
}
diff --git a/examples/with-zustand/pages/_app.js b/examples/with-zustand/pages/_app.js
index fef3255d9c39f..082837c7aac24 100644
--- a/examples/with-zustand/pages/_app.js
+++ b/examples/with-zustand/pages/_app.js
@@ -1,12 +1,10 @@
-import { StoreProvider } from '../lib/zustandProvider'
-import { useHydrate } from '../lib/store'
+import { useHydrate, Provider } from '../lib/store'
export default function App({ Component, pageProps }) {
const store = useHydrate(pageProps.initialZustandState)
-
return (
-
+
-
+
)
}
diff --git a/examples/with-zustand/pages/ssr.js b/examples/with-zustand/pages/ssr.js
index fd1c9190d9ba7..c7ba357021700 100644
--- a/examples/with-zustand/pages/ssr.js
+++ b/examples/with-zustand/pages/ssr.js
@@ -14,6 +14,10 @@ export function getServerSideProps() {
zustandStore.getState().tick(Date.now(), false)
return {
- props: { initialZustandState: JSON.stringify(zustandStore.getState()) },
+ props: {
+ // the "stringify and then parse again" piece is required as next.js
+ // isn't able to serialize it to JSON properly
+ initialZustandState: JSON.parse(JSON.stringify(zustandStore.getState())),
+ },
}
}