Next.js 14中使用Zustand Persist页面刷新数值闪烁问题求助
解决Next.js 14中Zustand persist持久化数值的闪烁问题
问题根源
闪烁问题主要来自两个核心原因:
- 自定义
useStore钩子导致状态延迟更新:初始data为undefined,页面先渲染默认值0或空白,等useEffect触发后才更新为持久化存储的数值,造成视觉闪烁。 - 服务端与客户端Hydration不匹配:服务端渲染时没有
localStorage,Zustand只能用初始值0;客户端Hydrate阶段先显示服务端返回的0,随后persist中间件从本地存储加载真实值,导致数值跳变。
解决方案
1. 移除多余的自定义useStore钩子
Zustand原生的useCountStore已经可以直接获取和监听状态变化,这个自定义封装完全没必要,反而会引入状态更新延迟的问题。
2. 消除Hydration数值差异
通过判断客户端环境,确保只有在客户端加载完成后才显示持久化的数值,避免服务端初始值与客户端真实值的冲突。
修改后的代码
app/page.tsx
'use client' import Button from '@mui/material/Button' import { useCountStore } from '@/app/store/useCountStore' import { useEffect, useState } from 'react' const Home = () => { const { num, increaseNum, decreaseNum } = useCountStore() // 标记是否已进入客户端环境 const [isClientReady, setIsClientReady] = useState(false) useEffect(() => { // 仅在客户端触发,确认环境就绪 setIsClientReady(true) }, []) return ( <> {/* 客户端就绪前显示服务端一致的初始值,避免Hydration不匹配 */} <div className='text-[red] text-[24px]'>{isClientReady ? num : 0}</div> <Button onClick={increaseNum} variant='contained'>increase number</Button> <Button onClick={decreaseNum} variant='contained'>decrease number</Button> </> ) } export default Home
store/useCountStore.ts(保持原代码即可)
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后,Zustand会直接响应状态变化,不会出现延迟更新的情况。 - 通过
useEffect标记客户端就绪状态,确保服务端渲染时显示与初始值一致的内容,客户端加载完成后再切换为持久化的真实数值,彻底消除Hydration不匹配导致的闪烁。
内容的提问来源于stack exchange,提问作者webnoooob
相关产品推荐
相关产品推荐

