React组件中鼠标事件处理函数内无法设置样式的问题
问题解答
1. 只读属性的本质
你遇到的TypeError,是因为React在把buttonStyle对象作为style prop传递给DOM按钮后,会将这个对象冻结为只读状态,防止意外修改导致渲染不一致。你在事件回调里直接修改buttonStyle.backgroundColor,其实是在修改已经被React冻结的对象属性,所以触发了只读错误,这和你用let声明buttonStyle无关。
2. 为什么用let还是只读?
let只是允许你重新赋值buttonStyle变量,但对象本身的可修改性被React的内部处理逻辑覆盖了——React会冻结用于DOM渲染的style对象,不管你用let还是var声明这个对象,只要它被传入了DOM元素的style prop,后续修改它的属性都会触发只读错误。
3. 正确的解决方法
React的渲染依赖状态变化,你应该通过状态驱动样式变化,而不是直接修改普通对象。这里有两种靠谱的实现方式:
方式一:基于hover状态动态生成样式对象
这其实就是你注释掉的if-else逻辑的优化写法,每次组件渲染时,都会根据hover状态生成新的buttonStyle对象,完全避开修改只读对象的问题:
import React, { useState } from "react"; function App() { let [ hover, setState] = useState(false); // 每次渲染根据hover状态生成新的样式对象 let buttonStyle = { backgroundColor: hover ? 'black' : '' } function hoverActive(){ setState(true); } function hoverInactive(){ setState(false); } return ( <div className="container"> <h1>Hello</h1> <input type="text" placeholder="What's your name?" /> <button style={buttonStyle} onMouseEnter={hoverActive} onMouseLeave={hoverInactive}>Submit</button> </div> ); } export default App;
方式二:用useState直接管理样式对象
如果需要更复杂的样式管理,也可以把样式对象本身放进状态里:
import React, { useState } from "react"; function App() { let [ buttonStyle, setButtonStyle] = useState({ backgroundColor: '' }); function hoverActive(){ setButtonStyle({ backgroundColor: 'black' }); } function hoverInactive(){ setButtonStyle({ backgroundColor: '' }); } return ( <div className="container"> <h1>Hello</h1> <input type="text" placeholder="What's your name?" /> <button style={buttonStyle} onMouseEnter={hoverActive} onMouseLeave={hoverInactive}>Submit</button> </div> ); } export default App;
补充说明
你之前用if-else判断hover状态修改样式能正常工作,是因为那段逻辑在组件渲染阶段执行,每次都会生成新的buttonStyle对象,还没被React冻结就完成了赋值,所以不会报错;而事件回调是在渲染完成后触发的,此时buttonStyle已经被React冻结,修改就会报错。
内容的提问来源于stack exchange,提问作者Aravi
相关产品推荐
相关产品推荐

