1. setState基本特点

1. setState是同步执行的

setState是同步执行的,但是state并不一定会同步更新

2. setState在React生命周期和合成事件中批量覆盖执行

在React的生命周期钩子和合成事件中,多次执行setState,会批量执行

具体表现为,多次同步执行的setState,会进行合并,类似于Object.assign,相同的key,后面的会覆盖前面的

当遇到多个setState调用时候,会提取单次传递setState的对象,把他们合并在一起形成一个新的
单一对象,并用这个单一的对象去做setState的事情,就像Object.assign的对象合并,后一个
key值会覆盖前面的key值

const a = {name : 'kong', age : '17'}
const b = {name : 'fang', sex : 'men'}
Object.assign({}, a, b);
//{name : 'fang', age : '17', sex : 'men'}

name被后面的覆盖了,但是age和sex都起作用了

例如:

class Hello extends React.Component {
constructor(){
super();
this.state = {
name: 'aa'
}
}
componentWillMount(){
this.setState({
name: 'aa' + 1
});
console.log(this.state.name); //aa
this.setState({
name: 'aa' + 1
});
console.log(this.state.name); //aa
}
render() {
return <div>
<div>Hello {this.props.name}</div>
<div>Hello {this.state.name}</div>
</div>;
}
} ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);

componentWillMount中两个log均为初始状态aa,而render中的state.name则为aa2
componentWillMount中的setState均执行了,但是state的更新是延迟的,所以log出的state均为aa
而render中的state.name则在state更新之后,而且只有第二次的aa1起了作用

3. setState在原生事件,setTimeout,setInterval,Promise等异步操作中,state会同步更新

异步操作中setState,即使在React的钩子或合成事件中,state都不会批量更新,而是会同步更新,
多次连续操作setState,每次都会re-render,state会同步更新

2. setState的形式

setState(object,[callback]) //对象式,object为nextState
setState(function,[callback]) //函数式,function为(prevState,props) => stateChange

[callback]则为state更新之后的回调,此时state已经完成更新,可以取到更新后的state
[callback]是在setState之后,更准确来说是当正式执行batchUpdate队列的state更新完成后就会执行,不是在re-rendered之后

使用两种形式的setState,state的更新都是异步的,但是多次连续使用函数式的setState,
React本身会进行一个递归传递调用,将上一次函数执行后的state传给下一个函数,因此每次执行
setState后能读取到更新后的state值。

如果对象式和函数式的setState混合使用,则对象式的会覆盖前面无论函数式还是对象式的任何setState,
但是不会影响后面的setState。

例如:

function increment(state,props){
return {count: state.count + 1};
} function incrementMultiple(){
this.setState(increment);
this.setState(increment);
this.setState({count: this.state.count + 1});
this.setState(increment);
}

上面三个函数式的setState中间插入一个对象式的setState,则最后的结果是2,而不是4,
因为对象式的setState将前面的任何形式的setState覆盖了,但是后面的setState依然起作用

3. setState的基本过程

setState的调用会引起React的更新生命周期的4个函数执行。

shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate

当shouldComponentUpdate执行时,返回true,进行下一步,this.state没有被更新
返回false,停止,更新this.state

当componentWillUpdate被调用时,this.state也没有被更新

直到render被调用时候,this.state才被更新。

总之,直到下一次render函数调用(或者下一次shouldComponentUpdate返回false时)才能得到更新后的this.state
因此获取更新后的状态可以有3种方法:

1. setState函数式

2. setState在setTimeout,Promise等异步中执行

setStatePromise(updator) {
return new Promise(((resolve, reject) => {
this.setState(updator, resolve);
}));
} componentWillMount() {
this.setStatePromise(({ num }) => ({
num: num + 1,
})).then(() => {
console.log(this.state.num);
});
}

或者

function setStateAsync(nextState){
return new Promise(resolve => {
this.setState(nextState, resolve);
});
} async func() {
...
await this.setStateAsync({count: this.state.count + 1});
await this.setStateAsync({count: this.state.count + 1});
}

3. setState callback

setState({
index: 1
}}, function(){
console.log(this.state.index);
})

4. componentDidUpdate

componentDidUpdate(){
console.log(this.state.index);
}

4. setState批量更新的过程

在React的生命周期和合成事件执行前后都有相应的钩子,分别是pre钩子和post钩子,pre钩子会调用batchedUpdate方法将isBatchingUpdates变量置为true,开启批量更新,而post钩子会将isBatchingUpdates置为false

如下图所示:

isBatchingUpdates变量置为true,则会走批量更新分支,setState的更新会被存入队列中,待同步代码执行完后,再执行队列中的state更新。

而在原生事件和异步操作中,不会执行pre钩子,或者生命周期的中的异步操作之前执行了pre钩子,但是pos钩子也在异步操作之前执行完了,isBatchingUpdates必定为false,也就不会进行批量更新。

5. setState的缺点

1. setState有可能循环调用

调用setState之后,shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate 等生命周期函数会依次被调用(如果shouldComponentUpdate没有返回 false的话),如果我们在render、componentWillUpdate或componentDidUpdate中调用了setState方法,那么可能会造成循环调用,最终导致浏览器内存占满后崩溃

2、setState可能会引发不必要的渲染

可能造成不必要渲染的因素如下:
(1)新 state 和之前的一样。这种情况可以通过 shouldComponentUpdate 解决。
(2)state 中的某些属性和视图没有关系(譬如事件、timer ID等),这些属性改变不影响视图的显示。

3、setState并不总能有效地管理组件中的所有状态

因为组件中的某些属性是和视图没有关系的,当组件变得复杂的时候可能会出现各种各样的状态需要管理,这时候用setState管理所有状态是不可取的。state中本应该只保存与渲染有关的状态,而与渲染无关的状态尽量不放在state中管理,可以直接保存为组件实例的属性,这样在属性改变的时候,不会触发渲染,避免浪费

6. setState和replaceState的区别

setState是修改其中的部分状态,相当于Object.assign,只是覆盖,不会减少原来的状态
replaceState是完全替换原来的状态,相当于赋值,将原来的state替换为另一个对象,如果新状态属性减少,那么state中就没有这个状态了

7. 一个实例分析

上图的执行结果为 0 0 1 1 3 4

参考: http://www.360doc.com/content/17/0803/18/27576111_676420051.shtml
    https://blog.csdn.net/kongjunchao159/article/details/72626637
    https://blog.csdn.net/michellezhai/article/details/80098211
    https://www.cnblogs.com/danceonbeat/p/6993674.html
    https://segmentfault.com/a/1190000010682761
    https://segmentfault.com/a/1190000015821018

React的setState执行机制的更多相关文章

  1. React的setState分析

    前端框架层出不穷,不过万变不离其宗,就是从MVC过渡到MVVM.从数据映射到DOM,angular中用的是watcher对象,vue是观察者模式,react就是state了. React通过管理状态实 ...

  2. React: React的组件状态机制

    一.简介 在React中,有两个核心的默认属性,分别是state和props.state会记录组件的状态,React根据状态的变化,会对界面做相应的调整或渲染.props则是数据流向属性,React通 ...

  3. React中setState同步更新策略

    setState 同步更新 我们在上文中提及,为了提高性能React将setState设置为批次更新,即是异步操作函数,并不能以顺序控制流的方式设置某些事件,我们也不能依赖于this.state来计算 ...

  4. 初学React,setState后获取到的thisstate没变,还是初始state?

    问题:(javascript)初学React,setState后获取到的thisstate没变,还是初始state?描述: getInitialState(){ return {data:[]}; } ...

  5. React中setState学习总结

    react中setState方法到底是异步还是同步,其实这个是分在什么条件下是异步或者同步. 1.先来回顾一下react组件中改变state的几种方式: import React, { Compone ...

  6. React的setState学习及应用

    React的setState学习及应用 一:作用: setState() 将对组件 state 的更改排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件.这是用于更新 ...

  7. React组件setState

    注意: 1. 自定义组件首字母必须大写.这里是以函数表达式的方式定义子组件的. 2. 使用 ES6 的 class 关键字创建的 React 组件,组件中的方法遵循与常规 ES6 class 相同的语 ...

  8. React中setState 什么时候是同步的,什么时候是异步的?

    class Example extends React.Component { constructor() { super(); this.state = { val: 0 }; } componen ...

  9. React中setState方法说明

    setState跟新数据是同步还是异步? setState跟新数据是异步的. 如何用代码表现出来是异步的. 点击按钮更新数据,然后去打印这个值看一下 setState跟新数据是异步的 class Fa ...

随机推荐

  1. Python教程:Python中的for 语句

    Python 中的 for 语句与你在 C 或 Pascal 中可能用到的有所不同. Python教程 中的 for 语句并不总是对算术递增的数值进行迭代(如同 Pascal),或是给予用户定义迭代步 ...

  2. [JSON].getObj( keyPath )

    语法:[JSON].getObj( keyPath ) 返回:[JSON] 说明:返回指定键名路径的JSON对象,指定键名路径不存在时返回空的toJson对象(强烈建议使用 [JSON].exists ...

  3. hadoop3.0新特性及新功能

    Hadoop-3.0.0-alpha2版本发布,相比之前的hadoop-2.x有一系列的功能增强.但目前还是个alpha版本,有很多bug,且不能保证API的稳定和质量. 主要变化 Java最低版本要 ...

  4. Linux内核设计笔记11——定时器

    定时器与时间管理笔记 内核中的时间 时钟中断:内核中的系统定时器以某种频率触发中断,该频率可以通过编程预定. 节拍率HZ:时钟中断的频率称为节拍率. 节拍:相邻两次中断的时间间隔称为节拍,1/节拍率. ...

  5. SpringCloud IDEA 教学 (一) Eureka的简介与服务注册中心的建立

    写在开头 SpringCloud进来成为业界排名靠前的微服务框架,最核心功能就是搭建微服务,并在此基础上衍生出一系列功能,如断路器(Hystrix).断路监控.管理配置.Zuul.OAuth2等功能. ...

  6. POJ 2986 A Triangle and a Circle(三角形和圆形求交)

    Description Given one triangle and one circle in the plane. Your task is to calculate the common are ...

  7. lintcode-163-不同的二叉查找树

    163-不同的二叉查找树 给出 n,问由 1...n 为节点组成的不同的二叉查找树有多少种? 样例 给出n = 3,有5种不同形态的二叉查找树: 标签 卡特兰数 动态规划 思路 参考博客http:// ...

  8. week12 201621044079 流与文件

    作业12-流与文件 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 面向系统综合设计-图书馆管理系统或购物车 使用流与文件改造你的图书馆管理系统或购物车 ...

  9. intellij idea 之 CheckStyle 代码格式校验

  10. [Redis]在Windows下的下载及安装

    1.下载 下载地址: https://github.com/MSOpenTech/redis, 下载并解压到特定的目录. 2.启动Redis服务端 CMD -> redis-server.exe ...