Next.js中useReducer懒初始化调用localStorage提示未定义如何解决
问题原因
Next.js 预设开启服务端渲染(SSR/SSG),服务端运行环境不存在浏览器端的 window 全局对象,而 localStorage 是挂载在 window 下的 API。你在 useReducer 的懒初始化函数中直接调用 localStorage,代码会在服务端渲染阶段执行,自然会抛出 localStorage is not defined 的错误。
解决方法
有两种常用的稳妥实现方案:
方案1:将本地存储读取逻辑移入useEffect(最稳妥,无hydration不匹配问题)
useEffect 只会在客户端渲染阶段执行,完全不会触发服务端运行逻辑。你需要给useReducer设置默认初始值为空数组,新增首次挂载时读取本地存储的逻辑,配合对应的reducer初始化动作更新状态即可。
修改后的完整代码如下:
import React, { useState, createContext, useReducer, useEffect } from 'react' import { cartReducer } from 'reducers/CartReducers' export const CartStates = createContext() export const CartProvider = props => { const [cartVisibile, setCartVisible] = useState(false) // 移除懒初始化逻辑,初始值设为空数组 const [medicineToBuy, dispatch] = useReducer(cartReducer, []) // 新增:首次挂载时读取本地存储数据,更新购物车状态 useEffect(() => { const storageData = localStorage.getItem('Cart'); if (storageData) { // 你需要在cartReducer中新增对应的INIT_CART动作处理逻辑 dispatch({ type: 'INIT_CART', payload: JSON.parse(storageData) }) } }, []) // 原有存储逻辑保持不变 useEffect( () => { localStorage.setItem('Cart', JSON.stringify(medicineToBuy)) }, [medicineToBuy] ) const value = { visibility: [cartVisibile, setCartVisible], itemsInCart: [medicineToBuy], dispatch: dispatch, } return <CartStates.Provider value={value}>{props.children}</CartStates.Provider> }
对应的cartReducer需要新增初始化逻辑示例:
export const cartReducer = (state, action) => { switch(action.type) { case 'INIT_CART': return action.payload // 原有其他逻辑保持不变 default: return state } }
方案2:在懒初始化函数中添加客户端环境判断
如果你不想修改reducer逻辑,可以在懒初始化时先判断当前是否为浏览器环境,仅在客户端时读取localStorage:
const [medicineToBuy, dispatch] = useReducer(cartReducer, [],function(){ // 新增环境判断 if (typeof window === 'undefined') return [] const storageData = localStorage.getItem('Cart'); return storageData ? JSON.parse(storageData) : []; })
注意:该方案可能会导致服务端渲染输出的初始内容和客户端首次hydrate的内容不一致,如果你开启了严格模式的hydration校验会抛出警告,更推荐使用方案1。
内容的提问来源于stack exchange,提问作者Ye Min Htun
相关产品推荐
相关产品推荐

