React实现侧边栏展开收起:更新尺寸遇只读属性错误如何解决?
React侧边导航栏展开/迷你切换:解决TypeError修改只读style对象的问题
我想要实现类似AdminLTE的侧边导航栏展开/迷你切换功能,但在React中更新导航栏尺寸时遇到了错误。以下是我的测试代码,用
setTimeout模拟点击触发宽度变化,结果抛出TypeError: Cannot assign to read only property 'width' of object '#<Object>':import React, { Component } from 'react'; class SideNavBar extends Component { render() { let sideBarStyle = { 'height': '100%', 'backgroundColor': 'lightblue', 'width': "80px", 'position': 'absolute', 'top': '0', 'left': '0' } setTimeout(() => { sideBarStyle["width"] = "300px"; }, 1000) return ( <div style={sideBarStyle}> sidenavbar </div> ); } } export default SideNavBar;请问如何通过点击事件正确更新元素尺寸?
核心原因
这个问题我之前也碰到过,核心原因是你直接修改了React内联样式对象的属性——React会把传递给元素的style对象标记为只读(不可变),直接赋值修改会触发只读属性错误。正确的做法是通过**组件状态(state)**来管理样式变化,当state更新时,React会自动重新渲染组件并应用新的样式。
方法一:用State管理内联样式
我们可以把侧边栏的宽度存在组件的state里,通过点击事件更新state,从而触发样式变化:
import React, { Component } from 'react'; class SideNavBar extends Component { // 初始化state,默认是迷你宽度 state = { sidebarWidth: '80px' }; // 切换宽度的方法 toggleSidebar = () => { this.setState(prevState => ({ sidebarWidth: prevState.sidebarWidth === '80px' ? '300px' : '80px' })); }; render() { const sideBarStyle = { height: '100%', backgroundColor: 'lightblue', width: this.state.sidebarWidth, position: 'absolute', top: '0', left: '0', cursor: 'pointer', // 添加上手型,提示可点击 transition: 'width 0.3s ease' // 添加上过渡动画,和AdminLTE效果一致 }; return ( <div style={sideBarStyle} onClick={this.toggleSidebar}> sidenavbar </div> ); } } export default SideNavBar;
方法二:用CSS类切换(更推荐)
实际项目中,更推荐用CSS类来控制样式变化,这样代码更清晰,也方便扩展更多样式(比如导航文字的显示/隐藏):
首先定义CSS文件(比如SideNavBar.css):
.sidebar { height: 100%; position: absolute; top: 0; left: 0; background-color: lightblue; cursor: pointer; transition: width 0.3s ease; } .sidebar--mini { width: 80px; } .sidebar--expanded { width: 300px; }
然后修改组件:
import React, { Component } from 'react'; import './SideNavBar.css'; // 引入CSS文件 class SideNavBar extends Component { state = { isExpanded: false }; toggleSidebar = () => { this.setState(prevState => ({ isExpanded: !prevState.isExpanded })); }; render() { const sidebarClass = this.state.isExpanded ? 'sidebar sidebar--expanded' : 'sidebar sidebar--mini'; return ( <div className={sidebarClass} onClick={this.toggleSidebar}> sidenavbar </div> ); } } export default SideNavBar;
补充:原代码报错的深层原因
在你的原代码中,sideBarStyle是在render方法里创建的普通对象,但React在处理内联样式时,会把这个对象包装成只读的不可变对象。当你在setTimeout里尝试修改它的width属性时,就会触发只读属性的错误。而通过state管理的话,每次state更新都会重新创建新的样式对象,完美避开了直接修改只读对象的问题。
内容的提问来源于stack exchange,提问作者james
相关产品推荐
相关产品推荐

