React 之 state 数据改变页面不更新未重新渲染的 7 种情况 及 解决办法

1. 组件 render 渲染了一个对象, 当 state 已确定更新但视图未更新

2. 组件 render 渲染了一个列表, 当 state 改变视图更新异常

3. A 和 B 子组件共用一个父组件 state, 此时点击子组件 A 按钮更新了父组件 state, 但是子组件 B 视图不更新

4. 父子组件同时初始化, 子组件接收的值来自父组件异步获取的数据

5. 调用方法中 state 更新了, 但实时拿到的值还是旧的

6. 在 redux 中修改 state 页面未更新

7. 当列表循环渲染之后, 改变当前 item 页面数据不变

1. 组件 render 渲染了一个对象, 当 state 已确定更新但视图未更新

代码:

// 错误方式
const obj = this.state.obj; 
obj.forEach((e) => {
        xxxxx //省略的代码是改变了对象的值
}); 
this.setState({
    obj
});

解决办法: 浅拷贝方式获取对象并修改再赋值。

// 正确方式
const obj = [...this.state.obj]; 
obj.forEach((e) => {
        xxxxx //省略的代码是改变了对象的值
}); 
this.setState({
    obj
});

原因: 对象数组是引用方式 , 对于 react 来说它的值都是地址 (涉及到 tree diff),因为没有被重新赋值 (地址没有改变),所以 react 会认为仍然是之前的元素 (element),则不更新视图。

参考:

react 更新 state 后视图没有变化

react 学习笔记 - 解决 react 修改 state 对象,页面不刷新问题

2. 组件 render 渲染了一个列表, 当 state 改变视图更新异常

代码:

{this.state.string.split('').map((item,index)=><p key={index}>item</p>)}
//其中this.state.string = '1' 且每秒钟 +1 ,此时页面视图未发生变化

解决办法: key={index} 改成 key={item+index}。

原因: key 是唯一的. 而 1 和 10 在 split 后是 [1] 和[1,0], 他们都共有 1, 这时候就会导致组件状态问题。

参考: 

 react 列表渲染时为什么尽量不要把索引设置为 key 值

3. A 和 B 子组件共用一个父组件 state, 此时点击子组件 A 按钮更新了父组件 state, 但是子组件 B 视图不更新

解决办法: 同上 (2)。

原因: 同一个页面调用同的组件 (出现问题的组件) 的 key 都用了 index, 也会导致组件状态问题。

4. 父子组件同时初始化, 子组件接收的值来自父组件异步获取的数据

场景:

初始化 state.value=' ',

componentDidMount 时, 父组件异步获取数据赋给 state.value,

而子组件一同初始化 componentDidMount 中拿到的 state.value 还是空的。

解决办法:

// render中判断state.value不等于空,再加载子组件即可
render() {
    return (
        { this.state.value? <subComp value={this.state.value}>我是子组件</subComp> : '' }      
    );
}

原因: 因为子组件已经 componentDidMount 渲染完成了, 父组件异步获取数据就没办法拿到。

  • 拓展:  貌似 componentWillReceiveProps 是符合需求的, 但是我用过几次有出现问题搞不定需求就没再用了。

5. 调用方法中 state 更新了, 但实时拿到的值还是旧的

代码:

//默认string等于''
this.setState({
    string: '123'
})
console.log(this.state.string)//''

解决办法:

this.setState({
    string: '123'
},()=>{
    //setState后的回调
    console.log(this.state.string)//'123'
})

原因: react 还没更新 state, 打印就执行完毕了。

6. 在 redux 中修改 state 页面未更新

**解决办法: ** 请检查你的 state 是不是直接改变原 state 的, 记住不要直接修改 state。

原因:  reducer 中 state 是引用, 在 reducer 中改变 state 是错误的, 虽然 store 里面的 state 是改变了, 但是 react - redux 会认为 dispatch 前后的 state 没有改变,就不会重新渲染页面。

参考:

react State 改变,页面却没有改变

state 更新了,组件却没有更新

7. 当列表循环渲染之后, 触发事件改变事件对应的值, 视图不更新

还有一种情况是如下, 直接改变源数据发现是没有变化的, 只有触发视图重排才会有效果

obj.map(item=>{
    <span onClick={()=>{item.name=1}}>{item.name}<span>
})

原因:

对象内的数据没有做监听

解决办法:

想办法触发视图重排, 重排方法很多; 我暂时能想到的是添加一个 node 节点, 再删除; 如果你有其他好办法好想法可以留言一起学习讨论!


作者:拒绝996从我做起
链接:https://juejin.cn/post/6911627178970972174
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted @ 2022-06-23 14:18  SimoonJia  阅读(12588)  评论(0编辑  收藏  举报