我有下一个错误。我有两个变体的主题在我的应用程序-黑暗和光明。
下面是沙箱-https://codesandbox.io/p/sandbox/trusting-mestorf-1rc2xv?selection=%5B%7B%22endColumn%22%3A7%2C%22endLineNumber%22%3A11%2C%22startColumn%22%3A7%2C%22startLineNumber%22%3A11%7D%5D&file=%2Fpages%2Fboard%2F%5Bslug%5D.tsx
- 主题上下文. ts**
export const ThemeContext = createContext<{
theme: AppThemeInterface,
setTheme: Dispatch<SetStateAction<AppThemeInterface>>,
// eslint-disable-next-line no-unused-vars
updateThemeKey: (newThemeKey: ThemeKeys) => void,
}>({
theme: getTheme(ThemeKeys.DARK) // here is just object with props from interface,
setTheme: () => null,
updateThemeKey: () => null,
});
- AppThemeProvider. ts**这里我从LocalStorage接收theme_key,并通过该键获取主题,然后将其值设置为ThemeContext
export const AppThemeProvider = ({ children }: AppThemeProviderProps) => {
const [currentThemeKey, setCurrentThemeKey] = useLocalStorage<ThemeKeys>('theme_key', ThemeKeys.DARK);
const [theme, setTheme] = useState<AppThemeInterface>(getTheme(currentThemeKey));
const updateThemeKey = (value: ThemeKeys) => {
setCurrentThemeKey(value);
};
return (
<ThemeContext.Provider value={
{ theme, setTheme, updateThemeKey }
}>
<ThemeProvider theme={theme}>
{children}
</ThemeProvider>
</ThemeContext.Provider>
);
};
使用本地存储挂钩
import { useState } from 'react';
export const useLocalStorage = <T>(key: string, initialValue: T) => {
const [value, setValue] = useState<T>(() => {
if (typeof window === 'undefined') {
return initialValue;
}
const lcItem = localStorage.getItem(key);
const endVal = lcItem ? JSON.parse(lcItem) : initialValue;
localStorage.setItem(key, JSON.stringify(endVal));
return endVal;
});
const saveValue = (value: T): void => {
localStorage.setItem(key, JSON.stringify(value));
};
const onChangeValue = (value: T): void => {
saveValue(value);
setValue(value);
};
return [value, onChangeValue] as const;
};
使用这种设置,当LocalStorage中的键与dark不同时,如果LocalStorage中的键为light,则会出现下一个错误
**
- 属性
className
不匹配。服务器:
**
这是因为首先它被渲染为黑暗的主题,但随后它又重新渲染为光明的主题。
我不知道如何使它正确渲染
2条答案
按热度按时间ny6fqffe1#
qjp7pelc2#
问题
状态
value
将始终在服务器上使用initialValue
进行计算,但是,在客户端上计算时,将使用localStorage中的密钥(因为window
是在客户端上定义的)。例如,如果initialValue
在服务器上是"亮的",但是在localStorage中可能是"暗的",你会得到一个水合错误,因为状态中的value
不匹配。溶液
由于localStorage仅用于客户端,因此您需要在useEffect中计算主题值。简而言之,useEffect仅在客户端运行,因此您将始终在服务器和客户端使用
initialValue
,但仅在客户端上,一旦useEffect在浏览器中运行,它将重新计算。演示
下面是一个非常简单的demo,它基于localStorage中的值派生主题。
缺点
如果值不是
initialValue
,则使用客户端存储的值将导致UI Flink 。您可以通过将值移动到可在服务器端访问的外部资源来避免此 Flink 。例如,将此值保存到可使用下一个生命周期方法之一访问的数据库:getServerSideProps或getInitialProps。但这带来了另一个障碍:如何知道数据库中的哪个值属于当前用户?无论值是从客户端还是从服务器检索的,当使用它来动态设置全局值时,您都会遇到障碍。