javascript - 从useEffect动态呈现样式表?
问题描述
我正在尝试使用一个按钮(传递给另一个组件)来切换暗模式。最初,我加载了一个轻主题样式表。然后,切换主题按钮应删除页面上最新加载的样式表,并将状态设置为与当前状态相反的状态。
我的理解是,useEffect 将“看到”状态变化并开始执行。这就是我们加载新样式表的地方。该应用程序正确加载了初始样式表,并且切换按钮一次正常工作,但在那之后就不行了。第一次更改后,它会删除所有样式。使用 react 开发工具,看起来状态正在正确更新。我认为我对 useEffect 和/或 useState 的理解是错误的。任何指示或帮助表示赞赏!
import { useState, useEffect } from "react";
import Navi from "./Components/Layout/Navi";
import Price from "./Components/Price";
import { BrowserRouter as Router, Route } from "react-router-dom";
import { Container } from "react-bootstrap";
import About from "./Components/About/About";
require("bootswatch/dist/cosmo/bootstrap.min.css");
function App() {
const [theme, setTheme] = useState("light");
const toggleTheme = () => {
Array.from(document.getElementsByTagName("style")).slice(-1)[0].remove();
setTheme(theme === "dark" ? "light" : "dark");
};
useEffect(() => {
console.log("fire");
console.log(theme);
if (theme === "light") {
require("bootswatch/dist/cosmo/bootstrap.min.css");
} else if (theme === "dark") {
require("bootswatch/dist/slate/bootstrap.min.css");
} else {
console.log("Theme state not correctly set");
}
});
return (
<Router path="/">
<>
<div className="App">
<Navi toggleTheme={() => toggleTheme()} />
<Container>
<Route path="/" exact component={Price} />
<Route path="/about" exact component={About} />
</Container>
</div>
</>
</Router>
);
}
export default App;
解决方案
你的理解useEffect
似乎是准确的。当您期望它们执行时,它们正在执行。没有像您预期的那样发生的是import
.
当你require
创建一个 css 文件时,它会html
为你的 dom 添加一个标签。
<link rel="stylesheet" type="text/css" href="/styles/overrides.css">
require
输入另一个 CSS 文件并不能撤消require
已经发生的事情 - 它仍然被添加到您的浏览器样式表中。你可以把它想象成导入一个 JS 文件而不是渲染一个组件。
选项 1:添加您自己的<style>
标签
<style>
您最直接的选择是将两个文件作为字符串导入,然后在标签中应用所需的样式。这是“快速和简单”的选项,但包含一些权衡(例如,无论如何您都在包的样式中导入两个主题)。
import React, { useState } from "react";
// using inline webpack loaders for convenience of the example in Code Sandbox
import mainCSS from "!!raw-loader!./styles.css";
import altCSS from "!!raw-loader!./altstyles.css";
// Using helmet to bring the styles into the head (not necessary)
import { Helmet } from "react-helmet";
console.log(mainCSS);
export default function App() {
const [showAltStyles, setShowAltStyles] = useState(false);
return (
<div className="App">
<Helmet>
<style>{showAltStyles ? altCSS : mainCSS}</style>
</Helmet>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={() => setShowAltStyles(!showAltStyles)}>
Toggle Alt Styles
</button>
</div>
);
}
带有实现的示例代码沙箱。
选项 2:CSS 变量
一个更强大的选项是使用CSS 变量并使用设置属性的 css 类覆盖它们。这将需要更多的工作来适应您的 bootswatch 主题。
:root {
--primary: #FFFFFF;
}
.dark-theme {
--primary: #000000;
}
此选项通过交换为每种样式定义的变量来避免重复样式。如果您选择此选项,您应该考虑浏览器支持,以及您是否可以在不受支持的浏览器上设置主题。
推荐阅读
- python - Plotly Dash:根据绘图选择过滤 DataTable
- sql - 如何在 Informatica 表达式转换中实现 case when 语句
- c++ - C++“类枚举”新手问题
- angular - 角度 7 如何将 ngx-datatable 内容导出到 Excel 工作表?
- file-upload - 带有文件夹选择的 Vaadin 8 多重上传
- c++ - 字符串十六进制到字节数组
- javascript - 添加一个 java 程序以在 Android Studio 应用程序中运行
- c++ - 如何编写一个非常简单的 TCP 服务器-客户端系统,其中客户端侦听 4 字节整数数据?
- mysql - 使用两个 INT 值作为日期
- azure-active-directory - 无法使用 Microsoft Graph SDK 创建事件