Next.js 14中如何正确使用localStorage?
优化Next.js 14中LocalStorage购物车存储的方案
你的问题核心在于初始化时机延迟导致的数值闪烁,以及冗余组件的不合理性,以下是具体优化方案:
方案一:手动整合LocalStorage到Zustand Store(无需额外组件)
直接在Store初始化阶段读取LocalStorage(仅在客户端执行),让组件渲染时直接拿到正确的初始值,避免useEffect延迟更新的问题:
// @/shared/stores/basketStore.js import { create } from 'zustand'; // 判断当前环境是否为客户端,避免服务器端报错 const isClient = typeof window !== 'undefined'; // 初始化时直接从LocalStorage读取数据,没有则用空数组 const initialBasket = isClient ? JSON.parse(localStorage.getItem('basket') || '[]') : []; export const useAddBasket = create((set) => ({ basket: initialBasket, // 派生计算总数量,不用单独存储,避免冗余 get totalItems() { return this.basket.reduce((sum, item) => sum + item.quantity, 0); }, // 添加商品时同步更新LocalStorage addItem: (item) => set((state) => { const newBasket = [...state.basket, item]; if (isClient) localStorage.setItem('basket', JSON.stringify(newBasket)); return { basket: newBasket }; }), // 删除商品同理,同步LocalStorage removeItem: (itemId) => set((state) => { const newBasket = state.basket.filter(item => item.id !== itemId); if (isClient) localStorage.setItem('basket', JSON.stringify(newBasket)); return { basket: newBasket }; }) }));
优势:
- 移除了冗余的
LocalStorage组件,逻辑更集中 - 页面刷新时组件直接读取初始化好的Store数据,不会出现从0到正确值的闪烁
- 所有购物车操作自动同步LocalStorage,无需单独维护
方案二:使用Zustand官方Persist中间件(更简洁)
Zustand提供了persist中间件,自动处理Store与LocalStorage的同步,无需手动写读写逻辑:
// @/shared/stores/basketStore.js import { create } from 'zustand'; import { persist, createJSONStorage } from 'zustand/middleware'; export const useAddBasket = create( persist( (set, get) => ({ basket: [], // 实时计算总数量,不存储到LocalStorage get totalItems() { return get().basket.reduce((sum, item) => sum + item.quantity, 0); }, addItem: (item) => set((state) => ({ basket: [...state.basket, item] })), removeItem: (itemId) => set((state) => ({ basket: state.basket.filter(item => item.id !== itemId) })) }), { name: 'basket-storage', // LocalStorage的存储key storage: createJSONStorage(() => localStorage), // 只持久化basket字段,totalItems通过计算得到,避免冗余存储 partialize: (state) => ({ basket: state.basket }) } ) );
优势:
- 完全托管LocalStorage的读写逻辑,代码更简洁
- 初始化时自动从LocalStorage加载数据,无闪烁问题
- 内置序列化/反序列化,无需手动处理JSON.parse/stringify
原方案问题解析
你之前的实现用useEffect在组件挂载后才初始化Store,导致:
- 组件首次渲染时拿到的是Store的初始0值,之后才被
init更新,出现数值闪烁 - 额外的
LocalStorage组件增加了冗余逻辑,不符合关注点分离原则
内容的提问来源于stack exchange,提问作者ffsdfdfadf
相关产品推荐
相关产品推荐

