深入理解React State 原理

目录
  • 问题:setState 到底是同步还是异步的?
  • 类组件state
  • setState原理揭秘
  • 函数组件state

问题:setState 到底是同步还是异步的?

如果对 React 底层有一定了解,可以回答出 batchUpdate 批量更新概念,以及批量更新被打破的条件。

答案:有时是同步,有时是异步。

在 合成事件 和 生命周期函数 里是 异步 的在 原生事件 和 setTimeout、promise里是 同步

造成setState的异步并不是由内部的异步代码引起的,在本身的执行过程中时同步的,但是合成事件和生命周期函数的调用顺序在更新之前,导致在内部不能直接得到更新后的值,可以用第二个参数 callback 来获取。

具体解释:可参考setState的执行过程

类组件state

setState(obj,callback)

  • 第一个参数:当 obj 为一个对象,则为即将合并的 state ;如果 obj 是一个函数,那么当前组件的 state 和 props 将作为参数,返回值用于合并新的 state。
  • 第二个参数 callback :callback 为一个函数,函数执行上下文中可以获取当前 setState 更新后的最新 state 的值,可以作为依赖 state 变化的副作用函数,可以用来做一些基于 DOM 的操作。

一次事件中触发一次如上 setState ,在 React 底层执行过程:

render 阶段 render 函数执行 -> commit 阶段真实 DOM 替换 -> setState 回调函数执行 callback

首先,setState 会产生当前更新的优先级(老版本用 expirationTime ,新版本用 lane )。接下来 React 会从 fiber Root 根部 fiber 向下调和子节点,调和阶段将对比发生更新的地方,更新对比 expirationTime ,找到发生更新的组件,合并 state,然后触发 render 函数,得到新的 UI 视图层,完成 render 阶段。接下来到 commit 阶段,commit 阶段,替换真实 DOM ,完成此次更新流程。此时仍然在 commit 阶段,会执行 setState 中 callback 函数,到此为止完成了一次 setState 全过程。

setState原理揭秘

本质:React 底层调用 Updater 对象上的 enqueueSetState 方法

enqueueSetState():创建一个update,放入当前 fiber对象 的待更新队列中,最后开启调度更新,进入更新流程。

React 的 batchUpdate 批量更新

目的:多次 setstate 会让逻辑多停留在 js 运行层面,阻塞了浏览器绘制,因此需要批量更新

batchedEventUpdates ():

分析流程:

  • React 事件执行前通过 isBatchingEventUpdates=true 打开开关,开启事件批量更新
  • 当事件结束,通过 isBatchingEventUpdates=false 关闭开关
  • 在 scheduleUpdateOnFiber 中根据这个开关来确定是否进行批量更新

1)异步环境下,继续开启批量更新模式:

异步操作里面的批量更新规则会被打破,因此提供了手动批量更新方法: unstable_batchedUpdates

2)提升更新优先级:

提供了方法: flushSync,可以将回调函数中的更新任务,放在一个较高的优先级中优先执行

补充:flushSync 在同步条件下,会合并之前的 setState | useState

3)总结:React 同一级别更新优先级 关系是:

flushSync 中的 setState > 正常执行上下文中 setState > 异步 setTimeout ,Promise 中的 setState

函数组件state

const [ state , dispatch ] = useState(initData)

  • ① state 目的提供给 UI ,作为渲染视图的数据源
  • ② dispatch 改变 state 的函数,可以理解为推动函数组件渲染的渲染函数
  • ③ initData 初始值

initData的初始值

  • 第一种情况是非函数,将作为 state 初始化的值
  • 第二种情况是函数,函数的返回值作为 useState 初始化的值

dispatch的参数

  • 第一种非函数情况,此时将作为新的值,赋予给 state,作为下一次渲染使用
  • 第二种是函数的情况,如果 dispatch 的参数为一个函数,这里可以称它为reducer,reducer 参数,是上一次返回最新的 state,返回值作为新的 state

监听 state 变化

useEffect :常可以把 state 作为 依赖项 传入 useEffect 第二个参数 deps ,但是注意 useEffect 初始化会默认执行一次

dispatch更新特点

与类组件一样,但是当调用改变 state 的函数dispatch,在本次函数执行上下文中,是获取不到最新的 state 值的

原因:函数组件更新就是函数的执行,在一次执行过程中,函数内部所有变量重新声明,所以改变的 state 只有在下一次函数执行时才更新。

useState 原理在之后 Hooks 讲解

问:类组件中的 setState 和函数组件中的 useState 有什么异同?

答:相同点:

  • 原理:setState 和 useState 更新视图,底层都调用了 scheduleUpdateOnFiber 方法,而且事件驱动情况下都有批量更新规则
  • 语法:第一个参数都可以传入函数

不同点:

  • 在不是 pureComponent 组件模式下, setState 不会浅比较两次 state 的值。只要调用 setState 就会执行更新。但是 useState 中 dispatchAction 会默认比较两次state是否相同来更新组件
  • setState 有专门监听 state 变化的回调函数 callback,可以获取最新 state。但是 useState 只能通过 useEffect 来执行 state 变化引起的副作用
  • setState 在底层处理逻辑时将旧 state 进行合并处理,而 useState 是重新赋值

到此这篇关于深入理解React State 原理的文章就介绍到这了,更多相关React State 原理 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 代码解析React中setState同步和异步问题

    React起源于Facebook的内部项目.React的出现是革命性的创新,React的是一个颠覆式的前端框架.在React官方这样介绍的它:一个声明式.高效.灵活的.创建用户界面的JavaScript库,即使React的主要作用是构建UI,但是项目的逐渐成长已经使得react成为前后端通吃的WebApp解决方案. angular中用的是watcher对象,vue是观察者模式,react就是state了,他们各有各的特点,没有好坏之分,只有需求不同而选择不同. React的官方网址:https:

  • React 三大属性之state的使用详解

    React中很多地方需要用到数据,这在React中被叫做状态,我们需要一个专门管理状态的方法,于是state相关的就诞生了.state应该被要求有两个基本功能,一,能够存储一定的值,从而能被react使用,二,能够再它改变的时候被React监听到并且重新渲染.这里分别介绍一下在类和函数组件中state的写法: 类组件 class ClassComponent extends React.Component{ constructor(props){ super(props) } //可写可不写 r

  • 浅谈React之状态(State)

    在React当中,当你更新组件的state,然后新的state就会重新渲染到页面中.在这个时候不需要你操作任何DOM.你也可以认为组件在React当中是一个状态机(State Machines).当用户进行操作时会实现不同的状态,然后再渲染到你的页面中,让你的页面与数据始终保持一致. 如何定义State 定义一个合适的State,是正确创建组件的第一步.State必须能代表一个组件UI呈现的完整状态集,即组件的任何UI改变,都可以从State的变化中反映出来:同时,State还必须是代表一个组件

  • 示例详解react中useState的用法

    useState useState 通过在函数组件里调用它来给组件添加一些内部 state.React 会在重复渲染时保留这个 state.useState 会返回一对值:当前状态和一个让你更新它的函数,你可以在事件处理函数中或其他一些地方调用这个函数.它类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并. 接下来通过一个示例来看看怎么使用 useState. 有这么一个需求:需要在 iframe 中加载外部网页. 初始的代码我们通过

  • 详解React中setState回调函数

    在使用React过程中,中可以使用this.state来访问需要的某些状态,但是需要更新或者修改state时,一般而言,我们都会使用setState()函数,从而达到更新state的目的,setState()函数执行会触发页面重新渲染UI.但是!!!setState是异步的!!! 1. 语法: setState(updater[, callback]) // updater是要改变的state对象,callback是state导致的页面重新渲染的回调,等价于componentDidUpdate

  • 浅谈使用React.setState需要注意的三点

    前言 这篇文章原标题是 3 Reasons why I stopped using React.setState ,但是我对原文作者提出的论点不是很感冒,但是作者提出的三点对 React 新手来说是很容易忽略的地方,所以我在这里只提出部分内容,而且把标题改为 使用React.setState需要注意的三点 . 正文 对 React 新手来说,使用 setState 是一件很复杂的事情.即使是熟练的 React 开发,也很有可能因为 React 的一些机制而产生一些bug,比如下面这个例子: 文档

  • 详解React setState数据更新机制

    为什么使用setState 在React 的开发过程中,难免会与组件的state打交道.使用过React 的都知道,想要修改state中的值,必须使用内部提供的setState 方法.为什么不能直接使用赋值的方式修改state的值呢?我们就分析一下,先看一个demo. class Index extends React.Component { this.state = { count: 0 } onClick = () => { this.setState({ count: 10 }) } re

  • 详解react setState

    setState是同步还是异步 自定义合成事件和react钩子函数中异步更新state 以在自定义click事件中的setState为例 import React, { Component } from 'react'; class Test extends Component { constructor(props) { super(props); this.state = { count: 1 }; } handleClick = () => { this.setState({ count:

  • react纯函数组件setState更新页面不刷新的解决

    目录 问题描述: 原因分析: 解决方案: 补:react中,hooks钩子时useState更新不渲染组件的问题 问题描述: const [textList, setTextList] = useState(原数组); setTextList(新数组); 当修改原数组时,如果原数组是个深层数组(不只一层),使用setTextList修改时,不会触发页面刷新 原因分析: 这个涉及到可变对象he不可变对象的知识,在vue和react中,如果更新可变对象时,可能会引起视图更新,这是因为,vue和rea

  • 深入研究React中setState源码

    React作为一门前端框架,虽然只是focus在MVVM中的View部分,但还是实现了View和model的绑定.修改数据的同时,可以实现View的刷新.这大大简化了我们的逻辑,只用关心数据流的变化,同时减少了代码量,使得后期维护也更加方便.这个特性则要归功于setState()方法.React中利用队列机制来管理state,避免了很多重复的View刷新.下面我们来从源码角度探寻下setState机制. 1 还是先声明一个组件,从最开始一步步来寻源: class App extends Comp

  • react学习笔记之state以及setState的使用

    在react中通过 state 以及 setState() 来控制组件的状态. state state 是 react 中用来存储组件数据状态的,可以类比成 vue 中的 data. 1.state的作用 state是React中组件的一个对象.React把用户界面当做是状态机,想象它有不同的状态然后渲染这些状态,可以轻松让用户界面与数据保持一致. React中,更新组件的state,会导致重新渲染用户界面(不要操作DOM).简单来说,就是用户界面会随着state变化而变化. 2.state工作

随机推荐