zustand坚持nextjs14

问题描述 投票:0回答:1

我正在使用 zustand 来保留我的号码,但刷新页面上的号码在闪烁,我该如何修复它。

enter image description here

我不确定是什么原因导致这个问题,似乎是服务器和客户端水合不正确导致的问题

这是我的应用程序/page.tsx

'use client'
import Button from '@mui/material/Button'
import { useCountStore } from '@/app/store/useCountStore'
import useStore from './store/useStore'

const Home = () => {
  const countStore = useStore(useCountStore, (state) => state)
  return (
    <>
      <div className='text-[red] text-[24px]'>{countStore?.num}</div>
      <Button onClick={countStore?.increaseNum} variant='contained'>increase number</Button>
      <Button onClick={countStore?.decreaseNum} variant='contained'>decrease number</Button>
    </>
  )
}
export default Home

这是我的商店/useCountStore

import { create } from 'zustand'
import { persist } from 'zustand/middleware'

interface countType {
    num: number,
    increaseNum: () => void,
    decreaseNum: () => void
}
export const useCountStore = create(persist<countType>((set, get) => ({
    num: 0,
    increaseNum: () => set({ num: get().num + 1 }),
    decreaseNum: () => set({ num: get().num - 1 }),
}), { name: 'count_storage_tag' }))

这是我的商店/useStore

'use client'
import { useState, useEffect } from 'react'

const useStore = <T, F>(
    store: (callback: (state: T) => unknown) => unknown,
    callback: (state: T) => F,
) => {
    const result = store(callback) as F
    const [data, setData] = useState<F>()

    useEffect(() => {
        setData(result)
    }, [result])

    return data
}

export default useStore
next.js persist zustand hydration
1个回答
0
投票

我怀疑如果你切换到

countStore?.num ?? 0
,它会显示
0
而不是闪烁(这实际上更好,但不是重点)

这个答案可能会有所帮助(关于cookie,但根本问题是相同的)

简而言之:
发生这种情况是因为客户端组件仍然在服务器上初始渲染(一次)。虽然名称可能有点令人困惑,但其想法是在用户浏览器重新水化之前为用户提供最好的“空 HTML shell”。
这很好,但是服务器无法访问 zustand 状态(仅是客户端),并且最终会在

countStore
中得到空值。客户端水合步骤完成后,该值就会出现。

您可以在 cookie 中保留 zustand 状态以与服务器共享(我不推荐这样做,主题变量可能除外)。最有可能的是,您应该保留状态客户端,并让服务器默认为组件的骨架版本。
只要骨架和实际内容的高度相同,用户体验就应该很棒。

例如:

<div className='text-[red] text-[24px]'>{countStore?.num ?? '-'}</div>

或者,

{countStore
    ? <div className='text-[red] text-[24px]'>{countStore.num}</div>
    : <Skeleton />}
© www.soinside.com 2019 - 2024. All rights reserved.