You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

优势:

  1. 移除了冗余的LocalStorage组件,逻辑更集中
  2. 页面刷新时组件直接读取初始化好的Store数据,不会出现从0到正确值的闪烁
  3. 所有购物车操作自动同步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 })
    }
  )
);

优势:

  1. 完全托管LocalStorage的读写逻辑,代码更简洁
  2. 初始化时自动从LocalStorage加载数据,无闪烁问题
  3. 内置序列化/反序列化,无需手动处理JSON.parse/stringify

原方案问题解析

你之前的实现用useEffect在组件挂载后才初始化Store,导致:

  1. 组件首次渲染时拿到的是Store的初始0值,之后才被init更新,出现数值闪烁
  2. 额外的LocalStorage组件增加了冗余逻辑,不符合关注点分离原则

内容的提问来源于stack exchange,提问作者ffsdfdfadf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 09:25:20