整理向,非原创,目的是整理出浅显易懂的方向性说明.
比如现有
this.state={name:"小明",age:18}
我们说修改组件的状态要用this.setState()来实现.这里有两个问题
1.为什么?我直接用this.state.age=17能不能实现重新渲染?
不能.因为它只是改变了这个组件当前的状态,并没有调用render().
2.this.setState()的原理是什么?
react中有一个原则:有变化,就一定返回一个新对象;没变化,原对象不做变化直接返回;
结合这个原则我们来分析一下原理:
参数:
this.setState()有三个参数:分别是this.state、nextState和callback.
其中,第一个参数是默认已经给的,为什么还要提出来是为了方便理解.
第二个参数是新状态,也就是我们期望组件能达到的状态.有多种方式.传一个对象或者传一个返回对象的函数.最终效果就是传一个对象.
this.setState({age:17})
第三个参数是设置成功之后的回调函数.
返回值:
this.setState()的返回值是一个新的对象,也就是说是一个新的状态.它使用了Object.assign(),将已修改的属性添加进去.而不是覆盖.
this.state里面有两个属性,如果我 this.setState({age:17}) 这么操作会不会导致this.state里面没有了"name"属性?
不会!我们上面刚说,this.setState()是返回一个新的对象,它会把有变动的改变成变动后的值,没有变动的保留.所以,你完全可以用这个方法去改变其中的某一个值.
接下来我们重点分析内部的原理:
首先,需要根据原来的this.state和传进来的参数来判断是否批量更改(是否批量差了一个收集待改组件的步骤),而这里的this.state是我之前说的默认传进来的.
然后,再根据this.state来计算nextstate. (shouldComponentUpdate()根据拿到的nextstate来返回一个布尔值,true则进行下一步,false,则下一步不执行.然后就进入componentWillUpdate)
接着render()出一个next组件,
最后根据diff算法进行更新渲染. 结束后进入生命周期函数componentDidUpdate()
这里也有几个问题:
(1)假如我调用this.setState()设置的值跟之前一样的,会不会重新渲染一次?
会!因为shouldComponentUpdate()默认肯定返回true,所以一定会往下执行.那为什么我要是根据nextstate返回一个布尔值呢?因为我们可以手动通过这种方式来控制render()来减少无用功,这是shouldComponentUpdate()的功能,只不过没有默认执行而已.
(2)假如我进行多次this.setState()的操作,而且都是同一个属性修改最终以哪次为主?
function stateChange() { this.setState({age: this.state.age + 1}); this.setState({age: this.state.age + 1}); this.setState({age: this.state.age + 1}); }
这里情况比较复杂,大体上可以理解为在react的体制内setState()是异步操作,所以最后this.state.age最终还是只加了1,比如onClick()这种react原生的事件中.但是体制外的是同步操作.最终会加3.
(3)为啥console.log()拿不到最新的this.state?
如第(2)点所说,setState()是异步操作.还记得上面所说this.setState()还有一个参数是回调函数吗?所以需要在this.setState()的参数里面再传一个回调函数,在函数中打印就能得到this.state.