React中如何在渲染前基于document.body属性设置state指定toggle默认选中值
问题根源
你的代码执行顺序逻辑颠倒:
- 组件
constructor会在挂载阶段最先执行,此时你还没有把localStorage存储的主题值同步到document.body上 componentDidMount是组件首次渲染完成后才触发的生命周期,所以constructor里读取到的data-theme永远是页面初始的默认值,不是用户本地存储的正确值- 另外你给checkbox的
defaultChecked传字符串值不符合规范,该属性接收布尔值作为参数,且仅会在组件首次渲染时生效,后续state变更不会更新checkbox状态,更适合用受控组件模式绑定checked属性。
修改方案
直接从数据源localStorage初始化状态,同时统一主题同步逻辑,将checkbox改为受控组件,修改后的完整代码如下:
class Theme extends Component { constructor(props) { super(props); // 优先从localStorage取主题,取不到默认用light const savedTheme = localStorage.getItem("data-theme") || "light"; // 提前同步主题到body,不需要等componentDidMount document.body.setAttribute("data-theme", savedTheme); this.state = { // dark主题时checkbox为选中状态,直接存布尔值 checked: savedTheme !== "light" }; this.handelChange = this.handelChange.bind(this); } handelChange(evt) { const currentChecked = evt.target.checked; const theme = currentChecked ? "dark" : "light"; // 更新body属性和本地存储 document.body.setAttribute("data-theme", theme); localStorage.setItem("data-theme", theme); // 更新state同步checkbox状态 this.setState({ checked: currentChecked }); let lineColor = getComputedStyle(document.body).getPropertyValue("--sidebar-color"); if (typeof InstallTrigger === "undefined") { lineColor = lineColor.substring(1); } this.props.colorChange(lineColor); }; render() { return ( <div onChange={this.handelChange} className="theme-switch-wrapper"> <label className="theme-switch" htmlFor="checkbox"> {/* 改用受控模式绑定checked属性,传入布尔值 */} <input type="checkbox" id="checkbox" checked={this.state.checked} /> <div className="slider round"></div> </label> </div> ); } } export default Theme;
调整说明
- 把主题读取、body属性同步逻辑提前到constructor阶段,确保初始化state时拿到的是正确的用户存储主题
- 将checkbox改为受控组件,绑定
checked属性和state,后续状态变更可以实时同步 - 统一了主题变更逻辑,避免重复代码
内容的提问来源于stack exchange,提问作者Saoma
相关产品推荐
相关产品推荐

