Next.js、Zustand和从本地存储加载初始状态

fnx2tebb  于 2023-10-18  发布在  其他
关注(0)|答案(2)|浏览(275)

在我的Zustand存储中,我尝试从本地存储中持久化的数据加载初始状态(我没有选择中间件,因为Next有一些我不想处理的问题):

const getInitialProject = (): Project => {
    const project = loadCurrentProjectFromLs()

    return (
        project ?? {
            projectName: '',
            cards: [],
        }
    )
}

const useProjectStore = create<ProjectStore>((set, get) => ({
    ...getInitialProject(),
...

然而,页面的第一次呈现是在服务器上完成的,而不是在客户端(In React and Next.js constructor, I am getting "Reference Error: localstorage is not defined"),这意味着本地存储在那个时候是不可访问的。
这意味着我的代码不能正常工作,因为状态只能在第一次渲染后更新,但导致Zustand初始化的钩子在第一次渲染时被触发。
有没有更好的方法来解决这个问题,而不是使用useEffect钩子,当localStorage变得可访问时更新存储?我希望逻辑是商店的一部分,而不是客户端,但我想不出比带计时器的循环更好的东西。

vptzau2j

vptzau2j1#

您可以使用中间件来保持状态。试试我为解决类似问题而创建的Persist and Sync中间件。
安装

$ pnpm add persist-and-sync
# or
$ npm install persist-and-sync
# or
$ yarn add persist-and-sync

然后将其添加到您的状态创建器中

import { create } from "zustand";
import { persistNSync } from "persist-and-sync";

type MyStore = {
    count: number;
    set: (n: number) => void;
};

const useStore = create<MyStore>(
    persistNSync(
        set => ({
            count: 0,
            set: n => set({ count: n }),
        }),
        { name: "my-channel" },
    ),
);

🎉只需几行代码,你的状态就可以在标签/窗口之间完美同步,并且还可以使用localStorage持久化!

wgxvkvu9

wgxvkvu92#

最后,我使用了一个带有useEffect的top布局文件,当LS可用时,它会在商店中触发加载函数。这样,函数至少不是页面的一部分,而是更广泛的基础设施(布局文件)。

const [hasInitializedStore, setHasInitializedStore] = useState(false)

    useEffect(() => {
        if (!hasInitializedStore && typeof window !== 'undefined') {
            loadCurrentProject()
            setHasInitializedStore(true)
        }
    }, [hasInitializedStore, loadCurrentProject])

相关问题