返回顶部
首页 > 资讯 > 精选 >useState执行流程使怎样的
  • 357
分享到

useState执行流程使怎样的

2023-06-27 11:06:06 357人浏览 独家记忆
摘要

这篇文章主要介绍“useState执行流程使怎样的”,在日常操作中,相信很多人在useState执行流程使怎样的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”useState执行流程使怎样的”的疑惑有所帮助!

这篇文章主要介绍“useState执行流程使怎样的”,在日常操作中,相信很多人在useState执行流程使怎样的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”useState执行流程使怎样的”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

作为 React 开发者,你能答上如下两个问题么:

  1. 对于如下函数组件:

function App() {  const [num, updateNum] = useState(0);  window.updateNum = updateNum;  return num;}

调用window.updateNum(1)可以将视图中的0更新为1么?

  1. 对于如下函数组件:

function App() {  const [num, updateNum] = useState(0);    function increment() {    setTimeout(() => {      updateNum(num + 1);    }, 1000);  }    return <p onClick={increment}>{num}</p>;}

在1秒内快速点击p5次,视图上显示为几?

1. 可以2. 显示为1

其实,这两个问题本质上是在问:

  • useState如何保存状态?

  • useState如何更新状态?

本文会结合源码,讲透如上两个问题。

这些,就是你需要了解的关于useState的一切。

hook如何保存数据

FunctionComponentrender本身只是函数调用。

那么在render内部调用的hook是如何获取到对应数据呢?

比如:

  • useState获取state

  • useRef获取ref

  • useMemo获取缓存的数据

答案是:

每个组件有个对应的fiber节点(可以理解为虚拟DOM),用于保存组件相关信息。

每次FunctionComponent render时,全局变量currentlyRenderingFiber都会被赋值为该FunctionComponent对应的fiber节点

所以,hook内部其实是从currentlyRenderingFiber中获取状态信息的。

多个hook如何获取数据

我们知道,一个FunctionComponent中可能存在多个hook,比如:

function App() {  // hookA  const [a, updateA] = useState(0);  // hookB  const [b, updateB] = useState(0);  // hookC  const ref = useRef(0);    return <p></p>;}

那么多个hook如何获取自己的数据呢?

答案是:

currentlyRenderingFiber.memoizedState中保存一条hook对应数据的单向链表

对于如上例子,可以理解为:

const hookA = {  // hook保存的数据  memoizedState: null,  // 指向下一个hook  next: hookB  // ...省略其他字段};hookB.next = hookC;currentlyRenderingFiber.memoizedState = hookA;

FunctionComponent render时,每执行到一个hook,都会将指向currentlyRenderingFiber.memoizedState链表的指针向后移动一次,指向当前hook对应数据。

这也是为什么React要求hook的调用顺序不能改变(不能在条件语句中使用hook) —— 每次render时都是从一条固定顺序的链表中获取hook对应数据的。

useState执行流程

我们知道,useState返回值数组第二个参数为改变state的方法

在源码中,他被称为dispatchAction

每当调用dispatchAction,都会创建一个代表一次更新的对象update

const update = {  // 更新的数据  action: action,  // 指向下一个更新  next: null};

对于如下例子

function App() {  const [num, updateNum] = useState(0);    function increment() {    updateNum(num + 1);  }    return <p onClick={increment}>{num}</p>;}

调用updateNum(num + 1),会创建:

const update = {  // 更新的数据  action: 1,  // 指向下一个更新  next: null  // ...省略其他字段};

如果是多次调用dispatchAction,例如:

function increment() {  // 产生update1  updateNum(num + 1);  // 产生update2  updateNum(num + 2);  // 产生update3  updateNum(num + 3);}

那么,update会形成一条环状链表。

update3 --next--> update1  ^                 |  |               update2  |______next_______|

这条链表保存在哪里呢?

既然这条update链表是由某个useStatedispatchAction产生,那么这条链表显然属于该useState hook

我们继续补充hook数据结构

const hook = {  // hook保存的数据  memoizedState: null,  // 指向下一个hook  next: hookForB  // 本次更新以baseState为基础计算新的state  baseState: null,  // 本次更新开始时已有的update队列  baseQueue: null,  // 本次更新需要增加的update队列  queue: null,};

其中,queue中保存了本次更新update的链表。

在计算state时,会将queue的环状链表剪开挂载在baseQueue最后面,baseQueue基于baseState计算新的state

在计算state完成后,新的state会成为memoizedState

为什么更新不基于memoizedState而是baseState,是因为state的计算过程需要考虑优先级,可能有些update优先级不够被跳过。所以memoizedState并不一定和baseState相同。

回到我们开篇第一个问题:

function App() {  const [num, updateNum] = useState(0);  window.updateNum = updateNum;  return num;}

调用window.updateNum(1)可以将视图中的0更新为1么?

我们需要看看这里的updateNum方法的具体实现:

updateNum === dispatchAction.bind(null, currentlyRenderingFiber, queue);

可见,updateNum方法即绑定了currentlyRenderingFiberqueue(即hook.queue)的dispatchAction

上文已经介绍,调用dispatchAction的目的是生成update,并插入到hook.queue链表中。

既然queue作为预置参数已经绑定给dispatchAction,那么调用dispatchAction就步仅局限在FunctionComponent内部了。

update的action

第二个问题

function App() {  const [num, updateNum] = useState(0);    function increment() {    setTimeout(() => {      updateNum(num + 1);    }, 1000);  }    return <p onClick={increment}>{num}</p>;}

在1秒内快速点击p5次,视图上显示为几?

我们知道,调用updateNum会产生update,其中传参会成为update.action

在1秒内点击5次。在点击第五次时,第一次点击创建的update还没进入更新流程,所以hook.baseState还未改变。

那么这5次点击产生的update都是基于同一个baseState计算新的state,并且num变量也还未变化(即5次update.action(即num + 1)为同一个值)。

所以,最终渲染的结果为1。

useState与useReducer

那么,如何5次点击让视图从1逐步变为5呢?

由以上知识我们知道,需要改变baseState或者action

其中baseState由 React 的更新流程决定,我们无法控制。

但是我们可以控制action

action不仅可以传,也可以传函数

// action为值updateNum(num + 1);// action为函数updateNum(num => num + 1);

在基于baseStateupdate链表生成新state的过程中:

let newState = baseState;let firstUpdate = hook.baseQueue.next;let update = firstUpdate;// 遍历baseQueue中的每一个updatedo {  if (typeof update.action === 'function') {    newState = update.action(newState);  } else {    newState = action;  }} while (update !== firstUpdate)

可见,当传时,由于我们5次action为同一个值,所以最终计算的newState也为同一个值。

而传函数时,newState基于action函数计算5次,则最终得到累加的结果。

如果这个例子中,我们使用useReducer而不是useState,由于useReduceraction始终为函数,所以不会遇到我们例子中的问题。

事实上,useState本身就是预置了如下reduceruseReducer

function basicStateReducer(state, action) {  return typeof action === 'function' ? action(state) : action;}

到此,关于“useState执行流程使怎样的”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: useState执行流程使怎样的

本文链接: https://lsjlt.com/news/309774.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • useState执行流程使怎样的
    这篇文章主要介绍“useState执行流程使怎样的”,在日常操作中,相信很多人在useState执行流程使怎样的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”useState执行流程使怎样的”的疑惑有所帮助!...
    99+
    2023-06-27
  • mysql的执行流程是怎样的?
    MySQL 可以分为 Server 层和存储引擎层两部分Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核 心服务功能,以及所有的内置函数,所有跨存储引 擎的功能都...
    99+
    2024-04-02
  • JS引擎执行流程是怎样的
    这篇文章给大家介绍JS引擎执行流程是怎样的,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。前言我强烈推荐的原因在于:在用动图的形式生动形象的讲述了JavaScript引擎基本原理。接触了...
    99+
    2024-04-02
  • MySQL中SQL执行流程是怎么样的
    这篇文章主要介绍MySQL中SQL执行流程是怎么样的,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!MYSQL体系结构先看一张架构图,如下:模块详解Connector:用来支持各种语言...
    99+
    2024-04-02
  • MySQL中SQL语句执行流程是怎么样的
    这篇文章主要介绍MySQL中SQL语句执行流程是怎么样的,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!总的来说,MySQL逻辑架构可以分为server层和存储引擎层这两个部分。这篇文...
    99+
    2024-04-02
  • Mysql 执行流程
    1、逻辑剖析 sql 执行流程为:sql语句 -> 查询缓存 -> 解析器 -> 优化器 -> 执行器。 1.1 服务器处理客户端请求 ​ 客户端程序 connectors >> 连接池 >> SQL接口 >> 解析器 >> 优化器 ...
    99+
    2020-07-21
    Mysql 执行流程
  • SpringMVC 执行流程
    SpringMVC 的执行流程 SpringMVC 框架 ​ SpringMVC 是一个基于 Java 的实现了 MVC 设计模式的请求驱动类型的轻量级 Web 框架,通过把 Model,View,...
    99+
    2023-09-04
    java 后端 mvc
  • vue watch执行流程
    Vue.js 是一个流行的前端框架,它提供了针对数据变化的处理机制。Vue 提供了一种 watch 的特性,可以用来监测 Vue 实例中数据的变化,并在发生变化时执行相应的操作。本文将介绍 Vue watch 的执行流程。创建 Vue 实例...
    99+
    2023-05-24
  • Oracle ASM Rebalance执行过程是怎样的
    这篇文章主要讲解了“Oracle ASM Rebalance执行过程是怎样的”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Oracle ASM Rebala...
    99+
    2024-04-02
  • mysql 执行流程解析
    Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核 心服务功能,以及所有的内置函数,所有跨存储引 擎的功能都在这一层实现,比如存储过程、触发器、视图等 而存储引擎层负责数据的存储和提取。其架构模式是...
    99+
    2021-01-18
    mysql 执行流程解析
  • 迭代器执行流程
    迭代器的执行流程,以及说明可迭代对象不一定是迭代器,但迭代器一定是可迭代对象   实例1 from collections import Iterable, Iterator import time class Classmate(...
    99+
    2023-01-30
    流程 迭代
  • springMVC执行流程详解
    springMVC执行流程 一,springMVC执行流程 1,MVC架构的由来 主要由model层,view层和controller层组成。 1.1,jsp模型 主要是结构简单,开发这个小型项目的效率高,主要是由这个jsp和javaBea...
    99+
    2023-08-18
    servlet java mvc 运维 mysql
  • mysql的sql语句执行流程
    1、client和server建立连接,client发送sql至server(对应连接器这一过程) 2、server如果在查询缓存中发现了该sql,则直接使用查询缓存的结果返回给client,如果查询缓存中...
    99+
    2024-04-02
  • python3 scrapy框架的执行流程
    scrapy框架概述:Scrapy,Python开发的一个快速,高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘...
    99+
    2024-04-02
  • SpringMVC的执行流程有哪些
    今天就跟大家聊聊有关SpringMVC的执行流程有哪些,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。#简易版客户发送请求经过 DisPatcherServlet 核心过滤器DisPa...
    99+
    2023-05-31
    springmvc
  • mapreduce的执行流程是什么
    MapReduce执行流程包括以下步骤: 输入数据划分:输入数据被划分成多个数据块,每个数据块包含若干个记录。 Map阶段:...
    99+
    2024-04-02
  • node中http模块的使用及执行流程
    在node中http有什么作用 http这个模块的职责就是帮你创建编写服务器 执行流程  1. 加载http模块 const http = require('htt...
    99+
    2024-04-02
  • Vue3中的执行流程思路分析-流程图
    目录一. 前言二. Vue3 思路分析1. createRender(options)2. createApp3. app.mount(‘#app’)4. r...
    99+
    2022-12-03
    Vue3执行流程 Vue3流程图 Vue3执行流程思路
  • Java程序执行基本流程
    下面由java学习教程栏目给大家介绍Java程序执行基本流程,希望对需要的朋友有所帮助!让我们来看看Java程序执行流程:例如hellojava.java文件,代码如下:  public class hellojava   {   publ...
    99+
    2014-11-27
    java教程 Java
  • swoole协程的执行流程是什么
    今天小编给大家分享一下swoole协程的执行流程是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。在swoole中,Swo...
    99+
    2023-06-29
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作