Stores (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 cause for buggy user interfaces. A store enables you to get under control even the most complex UI state logic.

A store works by representing state changes as atomic changes to an immutable data structure, enabling a fundamentally more robust state management.

In principle, you can use Vike with any store.

The documention on this page is about manually integrating stores.

🧠

Instead of manually integrating stores, we generally recommend using Vike extensions such as vike-vue-pinia.

⚠️ We recommend using this advanced capability, which can be complex, only if you have a clear reason for avoiding potentially simpler options.

💚

Contribution welcome to create Vike extensions integrating stores.

SSR

When using SSR, the initial state of the store is determined on the server side (during SSR) and then passed to the client side.

Initial state

If you're using SSR, you need to ensure that the store's initial state is exactly the same between the client- and server-side (otherwise you may get a hydration mismatch). Here's how you typically achieve this:

  1. Determine the store's initial state on the server-side (during SSR) and make it available as pageContext.storeInitialState.

    You typically create the store at onBeforeRenderHtml() and then retrieve its initial sate at onAfterRenderHtml():

    // pages/+onBeforeRenderHtml.js
     
    import { createStore } from 'awesome-store'
     
    export function onBeforeRenderHtml(pageContext) {
      pageContext.store = createStore()
    }
    // pages/+onAfterRenderHtml.js
     
    export function onAfterRenderHtml(pageContext) {
      pageContext.storeInitialState = pageContext.store.getState()
    }

    If you use React then you may also need to use +Wrapper:

    // pages/+Wrapper.jsx
     
    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. Make pageContext.storeInitialState available to the client-side by using passToClient.

    At pages/+config.js:

    // pages/+config.js
     
    export default {
      passToClient: ['storeInitialState']
    }
  3. On the client-side, initialize the store with pageContext.storeInitialState.

    Typically at onBeforeRenderClient():

    // pages/+onBeforeRenderClient.js
     
    import { createStore } from 'awesome-store'
     
    export function onBeforeRenderClient(pageContext) {
      pageContext.store = createStore(pageContext.storeInitialState)
    }

Data fetching

Typically, when using a store, your components never directly access fetched data: instead they only interact with the store and access data over the store.

If you're using SSR, you typically populate the store with initial data fetched on the server-side. You can achieve this by using pageContext.storeInitialState as shown above.