我正在使用 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
在初始状态下不起作用。每次都返回未定义。
这个问题很可能是因为在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;
},
这些优化将帮助您编写干净且优化的代码。
您收到此错误是因为 NextJS 首先在 NodeJS 服务器上运行。 NodeJS 没有
window.localstorage
对象。因此,您需要检查 window
对象是否可用,然后才调用它的方法。
if (typeof window !== "undefined") {
// Client-side-only code
}
另外,我建议您使用 redux-persist,它是
localstorage
的抽象。
这是一篇很好的文章,解释了如何将 redux-toolkit 和 redux-persist 与 NextJS 一起使用。
我在黑暗模式下遇到了同样的问题,我找到了三种解决方案,从最好到最差。
第一个是删除深色模式 Redux 切片并使用
next-themes
包处理主题。它让我可以完成之前使用 Redux Toolkit 所做的所有事情,而且效果更好。有效、易于实施(两行代码)并且可定制。它还避免了页面加载过程中的“闪烁”效果,这是当页面临时加载错误主题时发生的恼人的闪烁。
第二种,仅使用 Redux Toolkit,设置一个默认的初始值(例如
initialValue: true
),然后使用客户端上的 useEffect
钩子根据用户的偏好设置主题,并将值存储在 中localStorage
。该解决方案不会产生水合作用问题,但是,它具有“闪烁”效果问题。
第三个不太理想,是使用
dynamic()
的 next/dynamic
功能动态加载整个页面,并使用 SSR
选项禁用 { ssr: false }
。它有效,但您失去了 Next.js 的 SSR
优势。