我正在使用React作为前端创建一个静态Web应用程序,但遇到了一个动态主题化问题。虽然主题切换和将主题名称保存到本地存储中的操作正常,但在页面刷新或路径改变之前,它实际上只工作一次。
例如,我可以用之前选择的深色主题加载页面,但如果我切换回浅色主题,一切都正常,但另一次切换到深色主题会导致用户界面按预期改变颜色,但本地存储变量仍将保持浅色主题。
代码如下
这些是展示和改变主题的html卡片。
const ThemeCards = ( props ) => {
// eslint-disable-next-line
const [theme, setTheme] = useLocalStorage("theme-type", "theme-default");
var themeToggle = (themeName) => {
setTheme(themeName);
document.getElementById("themeProvider").className = themeName;
}
return (
<div className={props.className}>
<div className={props.className + "-inner"}>
<div className={props.className + "-front"}>
<div>{props.themeName}</div>
</div>
<div className={props.className + "-back"}>
<button onClick={() => themeToggle(props.themeID)}>Toggle</button>
</div>
</div>
</div>
)
}
这是useLocalStorage.js
import { useEffect, useState } from 'react';
const useLocalStorage = (storageKey, fallbackState) => {
const [value, setValue] = useState(
JSON.parse(localStorage.getItem(storageKey)) ?? fallbackState
);
useEffect(() => {
localStorage.setItem(storageKey, JSON.stringify(value));
}, [value, storageKey]);
return [value, setValue];
}
export default useLocalStorage;
实现,它只是一个div的id,以字符串的形式提供主题名称作为className
function App() {
const [theme, setTheme] = useLocalStorage("theme-type",
"theme-default");
return (
<>
<div className={theme} id="themeProvider">
<HashRouter>
<SideBar />
<NavTitle />
<Routes>
...
</Routes>
</HashRouter>
</div>
</>
);
}
export default App;
和版本
"react": "^18.1.0",
"react-dom": "^18.1.0"
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
刷新页面或简单地导航到主页路线,然后返回主题路线将重置循环。
我在控制台上记录了theme和themeName,希望在themeToggle中使用if语句进行调试
if (theme === themeName) {
console.log("Theme is already set to " + themeName);
return
} else {
setTheme(themeName);
document.getElementById("themeProvider").className = themeName;
}
虽然当错误发生时,本地存储中只存在一个变量,但切换到任何主题都会在控制台中生成控制台日志分支,就好像说本地存储键同时代表两个字符串一样,但由于我对在浏览器中持久化数据相当陌生,因此任何指导都将受到欢迎!
2条答案
按热度按时间ht4b089n1#
在React中,不建议直接使用getElementById来修改DOM。如果使用这种方法,很可能会让人感到困惑,因为现在DOM既受手动控制,又受React控制。
ThemeToggle(props.themeID)
有更多可疑的地方。大小写与var themeToggle
不匹配,所以它可能没有运行。在这个例子中,它是不必要的,所以应该用setValue
替换它。props.themeID
也很突出。传入的字符串正确吗?当你说“就好像说本地存储键同时代表两个字符串”时,你有没有试过在两个分支中都进行日志记录?React被允许在呈现新数据之前重新呈现相同的数据,因此它可能刚刚记录了以前的值。
我将给定的代码粘贴到一个新的create-react-app中,并让它按预期工作:
App.jsx:
App.css:
如果有必要将数据传递给应用的其余部分,则可以使用上下文扩展此示例。可以使用一对上下文提供程序来 Package 整个应用,一个提供
theme
,另一个提供setTheme
。可以使用useContext
检索它们。更高级的用例可以通过以下方式来满足:23c0lvtd2#
尝试将setting方法传递给child,看起来好像child更新主题时父代没有更新。
或使用a context