Store (State Management)
What is a store?
A store (aka state management) is a tool that helps you manage complex UI state.
Not properly managing UI state is one of the most common causes of buggy user interfaces. A store enables you to get even the most complex UI state logic under control.
A store works by representing state changes as atomic changes to an immutable data structure, enabling a fundamentally more robust state management.
We recommend using Vike extensions for automatically integrating state management tools.
React
Vue
💚Contribution welcome to create Vike extensions integrating stores with SSR.
You can also manually integrate any state management tool you want.
Manual integration
🧠Instead of manually integrating your store, we generally recommend using a Vike extension instead.
👉 We recommend using this advanced capability — which can be complex — only if you have a clear reason why simpler alternatives aren't an option for you.
Feel free to reach out if you want help integrating a store.
When using a store with SSR, the initial state of the store is determined on the server side (during SSR) and then passed to the client side.
You must ensure that the store's initial state is exactly the same on both the client- and the server-side (otherwise, you'll get a hydration mismatch).
The integration can be broken down into three steps:
1. SSR
Determine the store's initial state on the server-side (during SSR) and make it available as pageContext.storeInitialState
.
To achieve that, you can create the store at +onCreatePageContext.server.js
and then retrieve its initial sate at +onAfterRenderHtml.js
:
// pages/+onCreatePageContext.server.js
// Environment: server
import { createStore } from 'awesome-store'
export function onCreatePageContext(pageContext) {
pageContext.store = createStore()
}
// pages/+onAfterRenderHtml.js
// Environment: server
export function onAfterRenderHtml(pageContext) {
pageContext.storeInitialState = pageContext.store.getState()
}
If you use React then you may also need to use +Wrapper
:
// pages/+Wrapper.jsx
// Environment: server, client
import { Provider } from 'awesome-store/react'
import { usePageContext } from 'vike-react/usePageContext'
export default function StoreProvider({ children }) {
const pageContext = usePageContext()
return <Provider store={pageContext.store}>{children}</Provider>
}
2. passToClient
Make pageContext.storeInitialState
available on the client-side by using passToClient
:
// pages/+config.js
export default {
passToClient: ['storeInitialState']
}
3. Hydration
On the client-side, initialize the store with pageContext.storeInitialState
upon hydration, for example at +onBeforeRenderClient
:
// pages/+onBeforeRenderClient.js
// Environment: client
import { createStore } from 'awesome-store'
export function onBeforeRenderClient(pageContext) {
if (pageContext.isHydration) {
// Hydration. We must use the same state than on the server-side.
pageContext.globalContext.store = createStore(pageContext.storeInitialState)
} else {
// Client-side navigation. Nothing to do: the store was already initialized at hydration.
assert(pageContext.globalContext.store)
}
}
You can also use
+onCreateGlobalContext.client.js
instead to create the store earlier.
See also: