NextJS中刷新时localStorage购物车数据被重置为空的解决方法
解决Next.js购物车localStorage刷新重置及SSR报错问题
问题根源
- SSR报错原因:Next.js在服务器端渲染阶段不存在
window和localStorage对象,若直接在组件顶层或useState初始化时调用localStorage,会触发localStorage is not defined错误。 - 刷新后重置原因:组件挂载时,
cartItems初始值为空数组,触发依赖该状态的第二个useEffect,将空数组写入localStorage覆盖原有数据;随后第一个useEffect读取到的已是空值,导致购物车被重置。
修复方案
方案一:调整useEffect执行逻辑,避免初始空值覆盖
通过控制localStorage写入时机,确保仅在有效数据更新时同步存储,同时在客户端初始化时正确读取历史数据:
import { useState, useEffect, createContext } from 'react'; export const CartContext = createContext(); export function CartProvider({ children }) { // 初始state设为null,避免空数组触发不必要的存储 const [cartItems, setCartItems] = useState(null); // 客户端初始化:读取localStorage中的购物车数据 useEffect(() => { if (typeof window !== 'undefined') { try { const storedCartItems = localStorage.getItem('cartItems'); // 解析数据,确保返回数组格式 setCartItems(storedCartItems ? JSON.parse(storedCartItems) : []); } catch (err) { console.error('购物车数据解析失败', err); setCartItems([]); } } }, []); // 仅当cartItems完成初始化后,才同步到localStorage useEffect(() => { if (cartItems !== null && typeof window !== 'undefined') { localStorage.setItem('cartItems', JSON.stringify(cartItems)); } }, [cartItems]); // 等待state初始化完成,避免子组件拿到null值 if (cartItems === null) { return null; // 可替换为自定义加载组件 } // 购物车操作示例:添加商品 const addToCart = (item) => { setCartItems(prev => [...prev, item]); }; return ( <CartContext.Provider value={{ cartItems, addToCart }}> {children} </CartContext.Provider> ); }
方案二:使用useState工厂函数(Next.js 13+ App Router适配)
在App Router中,需先标记组件为客户端组件(添加'use client'指令),再通过useState工厂函数在客户端初始化状态:
'use client'; import { useState, useEffect, createContext } from 'react'; export const CartContext = createContext(); export function CartProvider({ children }) { // 工厂函数初始化:仅在客户端执行,避免SSR报错 const [cartItems, setCartItems] = useState(() => { if (typeof window !== 'undefined') { try { const stored = localStorage.getItem('cartItems'); return stored ? JSON.parse(stored) : []; } catch (err) { console.error('购物车数据解析失败', err); return []; } } return []; // 服务器端返回空数组,客户端会自动覆盖 }); // 同步购物车数据到localStorage useEffect(() => { if (typeof window !== 'undefined') { localStorage.setItem('cartItems', JSON.stringify(cartItems)); } }, [cartItems]); const addToCart = (item) => { setCartItems(prev => [...prev, item]); }; return ( <CartContext.Provider value={{ cartItems, addToCart }}> {children} </CartContext.Provider> ); }
核心注意事项
- 客户端组件标记:App Router中使用
localStorage的组件必须添加'use client'指令,否则会在服务器端执行时报错。 - 数据格式校验:解析
localStorage数据时添加try-catch,避免非法JSON格式导致的崩溃,同时确保返回值为数组类型。 - 初始化顺序:确保先读取历史数据再执行存储操作,避免初始空值覆盖原有数据。
内容的提问来源于stack exchange,提问作者ElendilTheTall
相关产品推荐
相关产品推荐

