两段React setState代码差异解析:为何后者触发重渲染前者不触发?
React状态更新不触发重渲染的原因解析
toggleOn 是一个在 onClick 事件中触发的函数。
以下是初始代码:这段代码能正常修改目标数据,但React不会将更新渲染到页面上。只有回到代码中保存后,组件才会重新渲染并展示更新后的内容。
const toggleOn = (ids) => { setboxData(prevBoxData => { prevBoxData.map(item => { if(item.id === ids){ item.on = !item.on; } return item; }) return prevBoxData; }) }
为什么下面这段代码能触发页面重渲染,而第一段却不行?
setboxData(prevBoxData => { let newData = []; prevBoxData.map(item => { if(item.id === ids){ item.on = !item.on; } newData.push(item); }) return newData; })
核心原因:React依赖状态的引用变化触发重渲染
React判断是否需要重渲染的逻辑是浅比较前后状态的引用:
- 第一段代码里,你直接修改了
prevBoxData数组中元素的on属性(属于直接修改原数据的变异操作),最后返回的还是原来的prevBoxData数组引用。React检测不到状态的引用变化,所以不会触发组件重渲染。 - 第二段代码中,你创建了新的数组
newData,最后返回的是这个新数组的引用。React检测到状态引用发生了改变,因此会触发组件重渲染,更新页面内容。
不过第二段代码仍有瑕疵:虽然数组是新的,但里面的元素还是原对象的引用,属于半变异操作。更规范的写法应该完全不修改原数据,返回新的对象:
const toggleOn = (ids) => { setboxData(prevBoxData => prevBoxData.map(item => item.id === ids ? {...item, on: !item.on} : item ) ) }
这种写法通过扩展运算符...创建新对象,既保证了数组是新引用,目标元素也是新对象,完全遵循React不可变状态的原则。
完整React组件代码
我的完整React组件代码
const Boxes = () => { const [boxData, setboxData] = React.useState(Data); const toggleOn = (ids) => { setboxData(prevBoxData => { prevBoxData.map(item => { if(item.id === ids){ item.on = !item.on; } return item; }) console.table(prevBoxData); }) } let boxes = boxData.map((item) => { console.log("Item in map: ",item) return( <Box bData = {item} handleClick = {toggleOn} /> ) }) return ( <div className='box-container'> {boxes} </div> ) }
内容的提问来源于stack exchange,提问作者Shubham
相关产品推荐
相关产品推荐

