The setState in React
· 2 min read
What#
在使用 React 时,并不能通过直接修改state里的数据使页面发生更新。React 没有像 Vue 一样使用Object.defineProperty或者
Proxy 的方式来监听数据变化。所以必须通过 setState方法告知 React 数据已经发生了更改。
该方法是从 Component 继承来的,源码中有具体实现。
异步更新#
异步更新很好理解,
this.state = { message: "Hello World"}// ...this.setState({ message: "Hello React"})console.log(this.state.message) // Hello World虽然已经告知 React 数据更新了,log 结果仍然是更新前的 message。这就是因为setState
是非同步的。
Why is setState asynchronous#
- 显著提高性能
- 使props和state保持同步
U can know more in here
How get synchronized data#
- 1、get it in callback function
this.setState({ message: "Hello React"},() => { console.log(this.state.message) // Hello React})- 2、use lifecycle function
当调用
renderfunction 执行完后会回调componentDidUpdate这个生命周期函数。👇
componentDidUpdate() { console.log(this.state.message) // Hello React}了解更多lifecycle function
Must setState be asynchronous#
- 在组件生命周期或 React 合成事件(onClick)中,
setState是异步; - 在
setTimeout或原生 DOM 事件中,setState是同步🕵️♂️
changeText() { setTimeout(() => { this.setState({ message: "你好呀,李银河" }) console.log(this.state.message) // 你好呀,李银河 }, 0)}componentDidMount() { const btnEl = document.getElementById("btn") btnEl.addEventListener('click',() => { this.setState({ message: "你好呀,李银河" }) console.log(this.state.message) // 你好呀,李银河 })}React 源码中对这两种情况进行了判断,从而导致不同的处理方式。
数据合并#
setState函数传入对象作为参数,为什么新的对象不对旧对象完全覆盖,而只是修改了同名属性。
其实是因为源码中使用了Object.assign() 函数。
// Object.assign({},prevState,partialState)Object.assign({},this.state,{message: "你好呀,李银河"})Why should not change state#
React 明确说明不推荐在 setState 中对 state 原数据(通常是引用类型)进行修改。
原因在于性能优化(或者 extends PureComponent)时会有问题🕵️♂️
shouldComponentUpdate(newProps, newState) { // 修改相同引用类型(Array)数据并不会走下行逻辑 if(newState.books !== this.state.books){ return true } return false}That's all