Next.js 中未定义初始状态的 localStorage

问题描述 投票:0回答:3

我正在使用 Redux Toolkit 在 Next.js 中创建一个项目。我尝试使用

localStorage
并收到错误“localStorage 未定义”,所以我转向
cookies-next
但这里也遇到了问题。请检查我的
themeSlice
页面:

import { createSlice } from "@reduxjs/toolkit"
import { getCookie, hasCookie, setCookie } from 'cookies-next'
const initialState = {
    name: hasCookie('theme')?getCookie('theme'):'light'
}
export const Theme = createSlice({
    name: "theme",
    initialState,
    reducers: {
        toggleTheme: (state, action) => {
            if(state.name === "light") {
                state.name = "dark"
                setCookie('theme', 'dark')
            } else {
                state.name = "light"
                setCookie('theme', 'light')
            }
        }
    }
})
export const {toggleTheme} = Theme.actions
export default Theme.reducer

在这里

initialState
,我每次都变得“亮”,甚至饼干也被减速机设置为黑暗。 问题是
getCookie
在初始状态下不起作用。每次都返回未定义。

javascript reactjs cookies next.js redux-toolkit
3个回答
0
投票

这个问题很可能是因为在reducer中设置cookie之前调用了getCookie函数。要解决此问题,您可以在设置 cookie 后使用 Next.js 组件中的 useEffect 挂钩来检索 cookie 的值:

import { useEffect, useState } from 'react';
import { getCookie } from 'cookies-next';

function YourComponent() {
  const [theme, setTheme] = useState('light');

  useEffect(() => {
    const cookie = getCookie('theme');
    if (cookie) {
      setTheme(cookie);
    }
  }, []);

  // ...
}

这样,主题状态的值将在设置后使用 cookie 的值进行更新。

代码看起来不错,但是,可以进行一些优化:

在initialState中使用对象解构:

const initialState = {
    name: hasCookie('theme') ? getCookie('theme') : 'light',
};

您可以使用三元运算符,而不是在toggleTheme缩减器中使用if-else语句:

toggleTheme: (state) => {
    state.name = state.name === 'light' ? 'dark' : 'light';
    setCookie('theme', state.name);
},

您还可以使用展开运算符来创建新对象,而不是改变现有状态:

toggleTheme: (state) => {
    const newState = {
        ...state,
        name: state.name === 'light' ? 'dark' : 'light'
    };
    setCookie('theme', newState.name);
    return newState;
},

这些优化将帮助您编写干净且优化的代码。


0
投票

您收到此错误是因为 NextJS 首先在 NodeJS 服务器上运行。 NodeJS 没有

window.localstorage
对象。因此,您需要检查
window
对象是否可用,然后才调用它的方法。

if (typeof window !== "undefined") {
  // Client-side-only code
}

另外,我建议您使用 redux-persist,它是

localstorage
的抽象。 这是一篇很好的文章,解释了如何将 redux-toolkit 和 redux-persist 与 NextJS 一起使用。


0
投票

我在黑暗模式下遇到了同样的问题,我找到了三种解决方案,从最好到最差。

第一个是删除深色模式 Redux 切片并使用

next-themes
包处理主题。它让我可以完成之前使用 Redux Toolkit 所做的所有事情,而且效果更好。有效、易于实施(两行代码)并且可定制。它还避免了页面加载过程中的“闪烁”效果,这是当页面临时加载错误主题时发生的恼人的闪烁。

第二种,仅使用 Redux Toolkit,设置一个默认的初始值(例如

initialValue: true
),然后使用客户端上的
useEffect
钩子根据用户的偏好设置主题,并将值存储在
localStorage
。该解决方案不会产生水合作用问题,但是,它具有“闪烁”效果问题。

第三个不太理想,是使用

dynamic()
next/dynamic
功能动态加载整个页面,并使用
SSR
选项禁用
{ ssr: false }
。它有效,但您失去了 Next.js 的
SSR
优势。

© www.soinside.com 2019 - 2024. All rights reserved.