setState() 将总是触发一次重绘,除非在 shouldComponentUpdate() 中实现了条件渲染逻辑。如果可变对象被使用了,但又不能在 shouldComponentUpdate() 中实现这种逻辑,仅在新 state 和之前的 state 存在差异的时候调用 setState() 可以避免不必要的重新渲染。
通常 state 中只来管理和渲染有关的状态 ,从而保证 setState 改变的状态都是和渲染有关的状态。这样子就可以避免不必要的重复渲染。其他和渲染无关的状态,可以直接以属性的形式保存在组件中,在需要的时候调用和改变,不会造成渲染。同时需要避免不必要的修改,当 state 的值没有发生改变的时候,尽量不要使用 setState 。虽然 shouldComponentUpdate 和PureComponent 可以避免不必要的重复渲染,但是还是增加了一层 shallowEqual 的调用,造成多余的浪费。
react setState后:
(1)React会将当前传入的参数对象与组件当前的状态合并,然后触发调和过程,在调和的过程中,React会以相对高效的方式根据新的状态构建React元素树并且重新渲染整个UI界面.
(2)React得到的元素树之后,React会自动计算出新的树与老的树的节点的差异,然后根据差异对界面进行最小化的渲染,在React的差异算法中,React能够精确的知道在哪些位置发生看改变以及应该如何去改变,这样就保证了UI是按需更新的而不是重新渲染整个界面.
setState—常规情况:在同一个方法中多次setState是会被合并的,并且对相同属性的设置只保留最后一次的设置;
import React from 'react';
export class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
//willmount中的setState会合并成一次执行,count只会保留最后一次的设置,
//前面的放弃,所以willmount之后是1,并不是3;并且在render之前执行,不会引起新的render
componentWillMount() {
let me = this;
me.setState({
count: me.state.count + 2
});
me.setState({
count: me.state.count + 1
});
}
//render之后执行didMount,setState做同样的处理,这是count是2,并且引起新的render
componentDidMount() {
let me = this;
me.setState({
count: me.state.count + 2
});
me.setState({
count: me.state.count + 1
});
}
onClick() {
let me = this;
me.setState({
count: me.state.count + 1
});
me.setState({
count: me.state.count + 1
});
}
//点击按钮,setState做同样处理,count是3,引起新的render
render() {
console.log(this.state.count);
console.log('1111111111111111111111111111111111111111111');
return (
<div>
<h1>{this.state.count}</h1>
<input type="button" value="点击我" onClick={this.onClick.bind(this)} /><br />
<br />
</div>
)
}
}
在React内部机制能检测到的地方, setState就是异步的;在React检测不到的地方,例如setInterval,setTimeout里,setState就是同步更新的
setState—定时器中的setState:定时器中的setState,每次都会引起新的render,即使是同一个定时器中的多次setState;
每次setState都会引发新的render,简单理解是定时器中的setState没走react的事物机制,执行时批量更新没被设置true,所以每次都直接render了.
setState—原生事件中的setState:在按钮原生事件中定义的setState,和定时器效果一样,每次setState都会引起新的render
react事件是合并的成一次render的;
componentDidMount() {
this.button.addEventListener('click', this.onClick.bind(this, '原生事件'), false);
}
//点击按钮,先执行原生事件,再执行react事件,但是原生事件会触发两次render,react事件触发一次。
onClick(info) {
console.log(info);
this.setState({
count: ++count
});
this.setState({
count: ++count
});
}
render() {
console.log(this.state.count);
return <div>
<input type="button" ref={input => this.button = input} onClick={this.onClick.bind(this, 'React事件')} value="生成计时器" />
<div>Count:{this.state.count}</div>
</div>
}
setState在react生命周期和合成事件会批量覆盖执行
在react生命周期和合成事件执行前后都有相应的钩子,分别是pre钩子和post钩子,pre钩子会调用batchedUpdate方法将isBatchingUpdates变量置为true,开启批量更新,而post钩子会将isBatchingUpdates置为false.在原生事件和异步操作中,不会执行pre钩子,或者生命周期的中的异步操作之前执行了pre钩子,但是pos钩子也在异步操作之前执行完了,isBatchingUpdates必定为false,也就不会进行批量更新。