DEV Community

Cover image for Next.js Zustand Integration Guide for Server and Client Components
Abdullah
Abdullah

Posted on

Next.js Zustand Integration Guide for Server and Client Components

Introduction

In this article, we try to implement Zustand with Next js app router to fetch data from server-side and store it with Zustand on client-side.


What is Zustand?

Zustand is a small, fast and scalable bearbones state management solution using simplified flux principles. Has a comfy API based on hooks, isn’t boilerplatey or opinionated.

To understand how to install and use Zustand you can read theZustand document.

What is the disadvantage of using state management systems on the server-side?

Server-side components are typically designed to be stateless. Whether you use Zustand or other state management systems as a workaround to introduce state on the server, it will maintain a global state shared among all users. This means that users can view what the previous user stored in the "state" on the server.

For instance, imagine your website has multiple pages accessible only after authentication. Here's an experiment: Place something restricted to authenticated users in a server-side Zustand store. Display it in a server-side component on a server-rendered page. Now, try accessing this page with two different users. If you store something specific to the first user and then load the page for the second user, you'll notice that the data from the first user has leaked into the page displayed for the second user.

So, What is the solution?

The workaround is to fetch data on the server-side page by adding "use server" to the top of the function body and passing the fetched data to other client-side components like the AppInitializer component to handle states with Zustand.

From this point on, Let’s get our hands dirty and do some coding.

Implementations:

Firstly, Create a folder in your /src path of the project called store and then create a store to handle our states for example we createuseStore :

import { create } from 'zustand'

export const useStore = create(() => ({
  user: null
}))
Enter fullscreen mode Exit fullscreen mode

After creating the store we need a component to set our fetched data from server-side in the Zustand store on client-side, let's call it AppInitializer. Then we should pass fetched data on server-side as props to the initializer component.

'use client'

import { useStore } from '@/store/useStore'

export default function AppInitializer({ user, children }) {
  useStore.setState({ 
    user,
    // ...
  })

  // ...
  return children
}

Enter fullscreen mode Exit fullscreen mode

In the last Next js, server components can use the inline function level or module level "use server" directive. To inline a Server Action, add "use server" to the top of the function body, so in our page we follow like this:

export default async function Page() {
  async function getUser() {
    'use server'
    const res = await fetch('https://api.example.com/...')
    const data = await res.json()
  }

  const user = await getUser()

  return (
    <AppInitializer user={user}>
      // ...    
    </AppInitializer>
  )
}
Enter fullscreen mode Exit fullscreen mode

Also you can move your fetching function's to the /actions/server path.

By using this architecture, we can incorporate every Next js server-side feature (like cookie) and after processing on server-side then render the app in client-side in order to store data in our state management like Zustand.

Thank you for reading, I hope that helps!
Also, you can find me on linkedin.

Top comments (0)