如何在NextJS 13.4中从服务器端持久化并设置客户端的全局状态?

huangapple go评论85阅读模式
英文:

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

问题

在NextJS 13中,例如,你的导航栏位于根目录的layout.tsx文件夹中。它会检查认证,然后获取用户信息,你希望用户信息在所有页面中都可以全局使用,无论是服务器组件还是客户端组件,因为导航栏存在于每个路由中,实际上是认证会话的真实来源,如果导航栏已经完成了工作,那么在所有服务器组件上都获取用户信息是不明智的。

英文:

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.

答案1

得分: 2

使用https://www.youtube.com/watch?v=OpMAH2hzKi8提供的解决方案。

使用Zustand,这是一个不需要上下文包装器的全局状态管理系统:
https://www.npmjs.com/package/zustand

创建一个存储库

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

创建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;
}

在根布局中

  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>
  );

现在只要布局在服务器端成功验证了用户,它就会设置用户。这还会防止默认值的闪烁。

英文:

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) =&gt; ({
  signedIn: false,
  setSignedIn: (isSignedIn) =&gt; set({ isSignedIn }),
}))

Create StoreInitializer.tsx:

&quot;use client&quot;;

import { useRef } from &quot;react&quot;;
import { useUserStore } from &quot;@/store/userStore&quot;;

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 (
    &lt;html lang=&quot;en&quot;&gt;
      &lt;body
 
      &gt;
        &lt;NextTopLoader /&gt;
        &lt;StoreInitializer user={user} /&gt;
        &lt;Navbar /&gt;
        {children}
        &lt;Footer /&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  );

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.

huangapple
  • 本文由 发表于 2023年5月28日 05:32:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76349135.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定