next.jsnext.js13

How to persist and set global state for client from server in NextJS 13.4?


PROBLEM: In NextJS 13, for example, your Navbar lives in the root layout.tsx folder. It checks auth, then fetches user, you want the user to be available globally to all pages regardless of server component or client component, since the Navbar exists in every route and is essentially the source of truth for the auth session, it would be unwise to fetch users on all server components when Navbar already did the work.


Solution

  • EDIT: better solution by tkdodo

    https://tkdodo.eu/blog/zustand-and-react-context#inject-comments

    OLD SOLUTION workaround:

    Solution by https://www.youtube.com/watch?v=OpMAH2hzKi8

    Using Zustand, a global state mangement system that doesn't require context wrappers: https://www.npmjs.com/package/zustand

    Create a store

    const useUserStore = create((set) => ({
      signedIn: false,
      setSignedIn: (isSignedIn) => set({ isSignedIn }),
    }))
    

    Create StoreInitializer.tsx:

    "use client";
    
    import { useRef } from "react";
    import { useUserStore } from "@/store/userStore";
    
    export function StoreInitializer({ user }: { user?: User }) {
      const isInitialized = useRef(false);
    
      if (!isInitialized.current) {
        useUserStore.setState({
          user,
        });
        isInitialized.current = true;
      }
      return null;
    }
    
    

    In root layout

      const { user } = await useServerGetAuth(); // ur own auth function
      useUserStore.setState({ user: user });
      return (
        <html lang="en">
          <body
     
          >
            <NextTopLoader />
            <StoreInitializer user={user} />
            <Navbar />
            {children}
            <Footer />
          </body>
        </html>
      );
    

    Now as long as the layout successfully auth'ed the user on the server side, it'll set the user. This will also prevent flash of default values.