React setState调用的原理

setState具体的执行过程如下:

  1. 首先调用setState()函数:
ReactComponent.prototype.setState = function(partialState, callback){// updater:一个带有形参的函数,返回被更新的状态对象。它可以接收到props和statethis.updater.enqueueSetState(this, partialState)if(callback){this.updater.enqueueCallback(this, callback, 'setState')}
}

enqueueSetState将新的state放进组件的状态队列里,并调用enqueueUpdate来处理将要更新的实例对象。

enqueueSetState: function (publicInstance, partialState) {// 根据 this 拿到对应的组件实例var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');// 这个 queue 对应的就是一个组件实例的 state 数组var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);queue.push(partialState);//  enqueueUpdate 用来处理当前的组件实例enqueueUpdate(internalInstance);
}

setState()最终通过enqueueUpdate更新state。

function enqueueUpdate(component) {ensureInjected();// 注意这一句是问题的关键,isBatchingUpdates标识着当前是否处于批量创建/更新组件的阶段if (!batchingStrategy.isBatchingUpdates) {// 若当前没有处于批量创建/更新组件的阶段,则立即更新组件batchingStrategy.batchedUpdates(enqueueUpdate, component);return;}// 否则,先把组件塞入 dirtyComponents 队列里,让它“再等等”dirtyComponents.push(component);if (component._updateBatchNumber == null) {component._updateBatchNumber = updateBatchNumber + 1;}
}

在enqueueUpdate中通过batchingStrategy的isBatchingUpdates属性来判断当前是否处于批量创建/更新组件的阶段。

batchingStrategy对象可以理解为“锁管理器”。这里的“锁”是指isBatchingUpdates变量。isBatchingUpdates初始值为false,表示并未进行任何批量更新操作。每当React调用batchedUpdate去执行更新动作时,会先把这个锁给锁上(置isBatchingUpdates为true),表明“现在正处于批量更新过程中”。当上锁后,更新需要更新的组件都要在队列中等待下一次批量更新。

setState()将对组件state的更新排入队列,并通知React需要使用更新后的 state重新渲染此组件及其子组件。你需要将setState()视为请求而不是立即更新state(可能为异步的!!!)。因为React会将多次的setState()放在一起一并执行,这样可以提升效率,减少页面渲染次数。

因为setState()并不总是立即更新state,可能会推迟更新。这导致在调用setState()后立即读取this.state有可能会拿到未更新之前的state。为了解决这个问题,我们可以使用componentDidUpdate或setState(updater, callback)的回调函数,保证在state更新后再执行。

总结:setState()用于更新状态,它接受两个参数,第一个参数可以传入一个对象,也可以传入一个updater函数传入的对象代表需要更新的状态及状态值。updater为一个带有形参的函数,返回被更新的状态对象,可以接收到state和props;第二个参数是一个可选的回调函数,在状态更新完后进行回调。setState()并不会立即执行状态的更新,而更像是更新状态请求。

  1. 在调用setState()后React会调用enqueueSetState()方法将需要更新的state入队。
  2. 接着调用enqueueUpdate方法里面的batchingStrategy.isBatchingUpdates属性判断当前是否处理批量更新的阶段。若处于,则将需要更新state的组件放入dirtyComponent队列中等待下一次批量更新;若不处于则立即更新组件。

setState调用之后发生了什么?是同步还是异步的?

在代码中调用setState后React会将传入的对象与当前组件的状态合并,然后触发调和过程。经过调和过程,React会根据新的状态构建React元素树,然后计算新老元素树节点的差异,根据差异对页面进行渲染。。

根据场景来决定是同步还是异步。

  • 同步:在React无法控制的地方,比如原生事件,例如:addEventListener、setTimeout、setInterval等事件中,就只能同步更新。
  • 异步:在React生命周期和合成事件中,React可以把多次setState合并到一起进行更新,提高效率。

setState设计为异步,可以提升性能。如果每次setState都要进行一次更新,那么意味着render函数会被频繁调用,这样效率很低。React采用延迟更新策略,可以把多次setState合并到一起进行更新,提高效率。

对于相同状态,同时调用setState,只有最后一个setState会生效,而不是单纯的累加

// 每次点击按钮value的值+2,而不是+3
<button onClick={() => (setValue(value + 1), setValue(value + 2)}
>value + 1
</button>

getDefaultProps和defaultProps

getDefaultProps和defaultProps用于指定属性的默认值。

// ES5
getDefaultProps: function(){return {autoPlay: false,maxLoops: 10}
},// ES6
// 静态函数:使某个函数只在一个源文件中有效,不能被其他源文件所用
static defaultProps = {name: "lsw"
}

setState的第二个参数是什么?

setState的第二个参数是一个回调函数,在组件重新渲染完后执行,等价于在componentDidUpdate中执行。在这个回调函数中可以拿到更新的后state的值。

setState和replaceState的区别是什么?

setState用来设置状态,它接收两个参数,第一个参数是新的状态值,第二个参数是一个可选的回调函数,在状态改变后执行,可以获取到状态改变后的值。
React会将多次的setState合并为一次执行,提高性能,减少页面渲染次数。setState只是覆盖原来的状态,不会减少原来的状态。

replaceState只会保留nextState中的值,原来的state将被删除,相当于赋值。

state和props的区别

props是从组件外部传入的,主要用于父组件向子组件传递数据,具有只读性,只能通过外部组件主动传递数据来渲染子组件。state的作用是组件自己用来创建、修改、管理自身状态,他是组件的私有属性,不可通过外部修改,只能在组件内部通过this.setState修改,修改state会导致页面重新渲染。

react setState详解相关推荐

  1. React 源码系列 | React Context 详解

    目前来看 Context 是一个非常强大但是很多时候不会直接使用的 api.大多数项目不会直接使用 createContext 然后向下面传递数据,而是采用第三方库(react-redux). 想想项 ...

  2. React.Children 详解

    React.Children 详解 React.Children提供了处理 this.props.children 的 API,this.props.children 支持任何数据(组件.字符串.函数 ...

  3. RN和React路由详解及对比

    前言 在平时H5或者RN开发时,我们业务场景中大部分都不是单页面的需求,那这时我们就能使用路由在进行多页面的切换.下面会对比一下react路由和RN路由的本质区别和使用方法. 路由(routing)是 ...

  4. rn php,RN和React路由详解及对比

    前言 在平时H5或者RN开发时,我们业务场景中大部分都不是单页面的需求,那这时我们就能使用路由在进行多页面的切换.下面会对比一下react路由和RN路由的本质区别和使用方法. 路由(routing)是 ...

  5. 【React】 详解下一代开源混合应用框架Reapp

    详解下一代开源混合应用框架Reapp reapp官网 转载于:https://www.cnblogs.com/dongdong230/p/4314978.html

  6. react中的setState详解

    1.setState更新状态的2种写法 (1). setState(stateChange, [callback])------对象式的setState ​ 1.stateChange为状态改变对象( ...

  7. React Hooks 详解

    文章目录 为什么会有Hooks? 什么是Hooks? 一.userState():状态钩子 二.useEffect():副作用钩子 三.useContext():共享状态钩子 四.useReducer ...

  8. setState详解

    我们都知道,React通过this.state来访问state,通过this.setState()方法来更新state.当this.setState()方法被调用的时候,React会重新调用rende ...

  9. react HOC详解

    高阶组件HOC HOC是react项目中对组件逻辑复用部分进行抽离的一种解决方案,它是一种设计模式. 表现形式为 一个函数,该函数接受一个组件为参数,并返回一个新组件. Example---- imp ...

最新文章

  1. 微信小程序修改整体背景颜色
  2. Facebook最新研究:配合AR眼镜使用的腕带,可将神经信号转化为动作
  3. 3 行 Python 代码实现假聊天机器人(慎入:这是假机器人!!!)
  4. linux 软件集成工具箱,在PB中动态修改SQL语句
  5. Android activity生命周期
  6. 16.PAE分页实验
  7. 处理数字_6_NULL值的列的个数
  8. uWSGI 和 nginx 的区别?
  9. R 学习 - 图形设置中英字体
  10. display:inline的用法
  11. 1031 查验身份证 (15 分) 一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。
  12. python怎么安装re模块_python模块模块re
  13. 小程序开发小游戏注意事项
  14. 摆动序列算法C语言,376 摆动序列 leetcode
  15. Miktex 安装遇到过的问题
  16. 01背包问题 动态规划求解方法 动态方程的详细解释 能理解的解释(附python代码)
  17. linux字体怪异_Linux默认安装的字体模糊难看
  18. 2014522420145238 《信息安全系统设计基础》 第五次实验
  19. flex布局——flex布局
  20. 魔兽世界服务器存档位置,选择服务器也有大学问?新手入坑《魔兽世界》该在哪里“扎根”...

热门文章

  1. Python进行RSA签名,支持SHAWithRSA,SHA256WithRSA
  2. Docker in docker 实现
  3. XTU OJ 1087
  4. 基于flask的YOLO目标检测web服务及接口
  5. AI技术人才成长路线图(附完整PPT)
  6. 黑马优购小程序之项目搭建
  7. 怎么在图片上直接编辑文字?分享两个编辑图片的方法
  8. 使用计算机备课 上课心得体会,计算机课程教学工作心得体会
  9. 客户端接收WIFI发送的数据
  10. 点击标题显示相应内容