React Hooks useState 使用详解+实现原理+源码分析

8 篇文章 1 订阅
订阅专栏

1. 简介

useState => 让函数组件具有维持状态的能力

useState 这个 Hook 是用来管理 state 的,它可以让函数组件具有维持状态的能力。即在一个函数组件的多次渲染之间,这个 state 是共享的。

2. 使用方法

useState<S>(initialState: (() => S) | S,): [S, Dispatch<BasicStateAction<S>>]{}

函数签名如下:

// 使用方法一:初始值为基础数据类型或Object
const [state, setState] = useState(initialState);

// 使用方法二:初始值为函数
const [state, setState] = useState(() => initialState);

@param useState 接受一个参数,作为 state 的初始值,这个参数可以是任何数据类型,也可以是函数
@return useState 返回一个数组,数组中包括 someState 数据源和更新这个 state 的方法 setSomeState

2.1 useState 使用示例

const [name, setName] = useState('React'); // 参数是String

const [age, setAge] = useState(9); // 参数是Number

const [features, setFeatures] = useState([{ text: 'JSX' }]); // 参数是Object

const [count, setCount] = useState(() => {
  // 先执行一定的逻辑,后再返回初始值
  const initialState = computedBaseCount(props);
  return initialState;
}); // 参数是Function

2.2 setState 使用示例:计数器函数组件

setSomeState 接收一个新的 state 值(这个参数可以是任何数据类型,也可以是函数),并将组件的一次重新渲染加入队列
普通更新: 直接赋值
函数式更新: 如果 new state 需要通过 old state 计算得出,可以给 setState 传入函数
__ 参数即为 old state
__ 返回值为 new state

function Counter({initialCount}) {
  // 声明一个叫做 “count” 的 state 变量
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {count}
      <button onClick={() => setCount(initialCount)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
    </>
  );
}

从这个例子中可以看到,useState 可以让我们非常方便的去设置一个 state(count),并提供一个特定的方法(setCount)来专门设置更新这个状态。

2.3 总结特点

  1. 惰性初始 stateinitialState 参数只会在组件的初始渲染中起作用,后续渲染时会被忽略;
  2. 函数式更新 state:可以为 setState 传入函数,来获取前一次 state 值;
  3. 语义化:每一个数据,都有一个专门设置状态的方法(即,一个函数有多个 setState)。

与类组件 setState 的区别:
○ 类组件中 setState 只能有一个,所以我们把一个对象作为一个 state,通过不同的属性来标识不同状态;
○ 函数组件中 setState 可有多个,更加语义化,更加方便使用。

什么样的值应该保存在 state 中呢?
这是日常开发中需要经常思考的问题。通常来说,我们要遵循的一个原则就是:state 中永远不要保存可以通过计算得到的值。比如说:

  1. props 传递过来的值。有时候 props 传递过来的值无法直接使用,而是要通过一定的计算后再在 UI 上展示,比如说排序。那么我们要做的就是每次用的时候,都重新排序一下,或者利用某些 cache 机制,而不是将结果直接放到 state 里。
  2. URL 中读到的值。比如有时需要读取 URL 中的参数,把它作为组件的一部分状态。那么我们可以在每次需要用的时候从 URL 中读取,而不是读出来直接放到 state 里。
  3. cookielocalStorage 中读取的值。通常来说,也是每次要用的时候直接去读取,而不是读出来后放到 state 里。

3. 源码分析👇👇👇

贴上的源码中,有些省略了异常处理、调试工具处理等非核心逻辑。(采用截图的方式,代码颜色利于识别)

3.1 Hook 公共的执行环境判断

React Fiber 会从 packages/react-reconciler/src/ReactFiberBeginWork.js 中的 beginWork() 开始执行

对于函数组件 FunctionComponent,其走以下逻辑加载或更新组件:
FunctionComponent源码.png

updateFunctionComponent 中,可看到 React Hooks 的渲染核心入口是 renderWithHooks
updateFunctionComponent源码.png
renderWithHooks 函数处理 Hooks 逻辑(省略异常处理代码和__DEV__处理逻辑)
renderWithHooks 主要做了两件事:

  1. 用变量 currentlyRenderingFiber记录当前的 fiber node。使得useState能拿到当前 node的状态。
  2. 判断 hook api 挂载在那个对象上。首次渲染和后期的更新,挂载的对象是不同的 => 解耦
    renderWithHooks源码.png
    HooksDispatcherOnMounted源码.png
    HooksDispatcherOnUpdate源码.png

可以看到,在组件首次渲染的时候,useState = mountState;非首次渲染,useState = upStateState

3.2 再来看mountState函数

mountState源码.png

第一步: 创建 hook 对象,并将该 hook 对象加到 hook 链的末尾

mountWorkInProgressHook源码.png

workInProgressHookhook 链表中的一个重要指针 => 它通过记录当前生成(更新)的 hook 对象,可以间接反映在组件中当前调用到哪个 hook 函数了。每调用一次 hook 函数,就将这个指针的指向移到该 hook 函数产生的 hook 对象上。
Hoook定义.png
Update定义.png

baseQueue
每次更新完会赋值上一个 update,方便 React 在渲染错误的边缘,数据回溯。
Update
称作一个更新,在调度一次 React 更新时会用到。
UpdateQueue
是 Update 的队列,同时还带有更新的 dispatch

第二步: 初始化 hook 对象的状态值,也就是我们传进来的 initState 的值。

第三步: 创建更新队列,这个队列是更新状态值的时候用的,会保存所有的更新行为。

第四步: 绑定 dispatchSetState 函数。

我们可以看到最后一行返回的就是这个函数。
也就是说这个函数,其实就是我们改变状态用的函数,就相当于是 setState 函数。这里它先做了一个绑定当前 quenefiber node 的动作,就是为了在调用 setState 的时候,知道该更改的是哪个组件的哪一个状态的值

3.3 改变状态的函数 dispatchSetState

useState 执行 setState 后会调用 dispatchSetState

下面来看看 dispatchSetState 都做了什么
dispatchSetState源码1.png
dispatchSetState源码2.png

我们可以看到实际上,dispatchSetState 这个函数主要做了两件事情。
第一件事:创建了一个 update 对象,这个对象上面保存了本次更新的相关信息,包括新的状态值 action
第二件事:将所有的 update 对象串成了一个环形链表,保存在我们 hook 对象的 queue.pending 属性上面。
环形链表流程图.jpg

使用环形链表的意义:
整个环形链表变量我们叫它 update,使得 queue.pending = update
那么此时 queue.pending 的最近一次更新,就是 update,最早的一次更新是 update.next
这样就快速定位到最早的一次更新了
如果是单链表,想找到最早的 一次更新,需要一层一层往下找
环形链表一次就找到了

3.4 updateState

updateState 是我们组件更新阶段,调用 useState 真正走的逻辑。

updateState源码.png

可以看到其实 updateState 的内部逻辑,其实是就是 updateReducer,所以其实 useState useReducer 两个 hooks 其实做的是同一件事 => 更新 state
updateReducer 相关源码解析,请看本篇文章

useStateuseReduer 的关系:
useStateuseReduer 的一个特殊情况,其传入的 reducer 是固定的 basicStateReducer,负责改变 state
useReducer 可以传入自定义的 reducer

updateState 做的事情,实际上就是拿到更新队列,循环队列,并根据每一个 update 对象对当前 hook 进行状态更新。最后返回最终的结果。

3.5 流程总结

useState流程图.png

reactuseState源码分析
weixin_59558923的博客
11-10 759
本文主要讲解了部分hooks的使用与原理,对hook使用更加熟悉了,还有一部分React内置hook使用请查看官网,还有基于React的扩展ahooks都是值得学习的。
前端面试】看react源码,解读useState
最新发布
hhhh
08-22 1054
mount 阶段获取当前 Hook 节点,同时将当前 Hook 添加到 Hook 链表中初始化 Hook 的状态,即读取初始 state 值创建一个新的链表作为更新队列,用来存放更新操作setXxx(),赋值给Hook.queue创建一个 dispatch 方法(即 useState 返回的数组的第二个参数:setXxx()),该方法的用途是用来修改state,赋值给queue.dispatch返回当前 state 和 修改state 的方法(dispatch)
useState源码浅析
weixin_33786077的博客
03-18 2616
欢迎到我的blog看这篇文章,阅读体验更好 前言 简单说下为什么React选择函数式组件,主要是class组件比较冗余、生命周期函数写法不友好,骚写法多,functional组件更符合React编程思想等等等。更具体的可以拜读dan大神的blog:传送门。其中Function components capture the rendered values这句十分精辟的道出函数式组件的优势。 ...
简单易懂的 React useState() Hook 指南(长文建议收藏)
热门推荐
pingan8787
01-06 1万+
作者:Dmitri Pavlutin译者:前端小智来源:dmitripavlutin.com腾讯云最近在做活动,百款云产品低至 1 折,可以点击 阅读原文 进行参与状态是隐藏在组件中的信...
React中的UseState的底层源码
m0_53164768的博客
04-30 190
手写usestate的底层原理
前端学习案例-React Hooks『useState』实现
qq_41632427的博客
08-11 270
o
React源码分析6-hooks源码
It_kc的博客
12-09 170
所以我们总结一下这个函数,它所做的事情如下:总结一下useStateuseReducer的执行过程如下图:总结一下useEffect的大体流程如下:本章讲解了 react hooks 的源码,理解了 hooks 的设计思想和工作过程。其他 hook 平时用的比较少,就不在这里展开讲了,但通过上面几个 hook源码讲解,其他 hook源码你应该也能看得懂。
Hooks 原理解析
baidulixueqin的博客
04-24 1794
Hooks 原理解析 内容 1.分析useState原理和源码 2.useRef的作用 3.useContext的作用 4.Vue3 对比 React 分析useState原理 import React from "react"; import ReactDOM from "react-dom"; const rootElement = document.getElementById("root"); function App() { console.log("App 运行了") const
PreactReact)核心原理详解
玄魂工作室
12-13 1983
原创: 宝丁 玄说前端 本文作者:字节跳动 - 宝丁 一、Preact 是什么 二、PreactReact 的区别有哪些? 三、Preact 是怎么工作的 四、结合实际组件了解整体渲染流程 五、Preact Hooks 结束语 2.1 事件系统 2.2 更符合 DOM 规范的描述 3.3.1 Diff children 3.3.2 Diff 3.3.3 Diff props 3.1 JSX...
React 源码系列 | React Context 详解
止水聊技术
09-04 899
目前来看 Context 是一个非常强大但是很多时候不会直接使用的 api。大多数项目不会直接使用 createContext 然后向下面传递数据,而是采用第三方库(re...
react_employee_directory_19-源码.rar
10-10
React Hooks如`useState`、`useEffect`和`useContext`等,使得在函数组件中也能实现类组件的功能,简化了代码,提高了开发效率。通过分析源码,我们可以学习如何在实际项目中应用这些Hooks。 3. **数据管理** 在...
hooks-useState
luo_qianyu的博客
07-30 374
hooks-useState 案例 function FunctionComponent(props) { // const [state, dispatch] = useState(1); return ( <div className="border"> <p onClick={()=>{ dispatch(2); }}>{props.name}{state}</p> </div&gt
从实现自己的useState入手理解React常见hooks源码
m0_57307213的博客
09-22 560
react-hooks源码
hooks之useState
CH的博客
04-01 330
import React, { Component, useState } from 'react' // 类写法 class App extends Component { constructor() { super() this.state = { count: 0, } } render() { const { count } = t...
react hooks实现原理useState为例)
qq_40511157的博客
08-22 695
一、源代码 逻辑十分绕,建议多敲几遍。 let isMount = true; // 判断是挂载还是更新 let workInProgressHook; // App组件对应的fiber对象 const fiber = { memorizedState: null, // 当前hook的相关信息 stateNode: App } function schedule() { // 更新前将workInProgressHook重置为fiber保存的第一个Hook workI
react hooks中的useState如何实现的
米斯特尔曾的博客
10-24 382
react useState如何实现的 import { useState } from 'react'; export function User() { const [name, setName] = useState(''); const [age, setAge] = useState(18); const onChangeName = (e) => { setName(e.target.value); } const onChangeAge = (e) => { se
react源码系列之由浅入深的useState
weixin_42373116的博客
04-10 1005
前言 今天的目的主要是学习下reacthooks之useState. 通过使用/ 手写/ 解读源码的方式来记录下学习过程。 首先要说明一点:为什么会用react hooks的出现?解决了什么问题? react类组件中可以设置state状态,可以添加生命周期的函数,但是需要每次都实例化消耗资源。 函数组件呢?写法简单但是无法保存状态。 所以react hook的出现就是为了在使用函数组件的时候,还能提供状态供其使用 开始 1. 使用 接下来我们先了解下用法,到底该如何使用呢??? impo
react hooks usestate
06-28
React Hooks useStateReact中的一个钩子函数,用于在函数组件中使用状态。它接受一个初始状态值作为参数,并返回一个数组,其中第一个元素是当前状态值,第二个元素是一个函数,用于更新状态值。使用useState可以...
写文章

热门文章

  • git clean 的用法详解_一定要学_一定要慎用 71504
  • 往GitLab提交代码、创建分支、合并分支的完整流程 31169
  • 正则表达式(二)常用正则表达式——验证真实姓名 16372
  • macOs Big Sur “ 无法打开×××,因为无法验证开发者。“ 14945
  • mac下如何运行sh脚本文件 12165

分类专栏

  • 浏览器 1篇
  • http 2篇
  • 大前端
  • JavaScript 15篇
  • TypeScript 2篇
  • HTML 2篇
  • CSS 5篇
  • ES6 2篇
  • React 8篇
  • Vue 4篇
  • 小程序 2篇
  • App 1篇
  • Flutter 10篇
  • NodeJS 2篇
  • 面试笔试题 13篇
  • 优化 5篇
  • 正则表达式 9篇
  • Git 13篇
  • VSCode 5篇
  • shell 5篇
  • 工具 6篇
  • Mac 8篇
  • 数据结构和算法 6篇

最新评论

  • 正则表达式(二)常用正则表达式——验证真实姓名

    LegalHighKing: 张三都检测不出来

  • 正则表达式(三)正则的捕获

    学前端的阿柴酱: 讲的很深,收藏了

  • git 提交,文件名大小写的修改提交不上去?解决办法在这里

    小小小奇迹: 提交是提交上去了,但是本地release上还是小写,导致每次checkout都会报错只能checkout -f强制切换了

  • git 提交,文件名大小写的修改提交不上去?解决办法在这里

    小小小奇迹: git config core.ignorecase false, 设置区分大小写后,远程仓库的小写版本会被覆盖掉的,不会有存在两个文件的问题的。

  • Vue Devtools(Google插件)安装教程

    苗瞄喵: https://blog.csdn.net/qq_49355028/article/details/128778127

大家在看

  • 基于Node.js+vue高校入学报到系统(开题+程序+论文) 计算机毕业设计 544
  • 《ESP32调试异常集锦》之移植I2C程序时i2c_master_cmd_begin返回-1
  • Linux运维篇-parted分区看到的容量大小和系统中实际的容量有出入
  • compareTo()方法详解
  • 【可白嫖源码】招聘管理系统(案例分析) 384

最新文章

  • React Hooks useRef 源码解读+最佳实践
  • 数据存储(三)WebStorage 之 IndexedDB
  • 数据存储(二)WebStorage 之 sessionStorage、globalStorage、localStorage
2023年1篇
2022年7篇
2021年14篇
2020年59篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

深圳坪山网站建设公司手机网站seo优化服务贵阳网站排名优化苏州seo网站优化方案东胜网站搜索优化网站排名优化廉价易速达网站优化1没基础学网站优化难吗普洱三亚营销型网站优化系统如何优化移动端网站佛山网站关键字优化公司网站优化标题怎么起济南网站seo优化代理霍城网站优化常桉网站优化优化网站建设哪家技术好佛山网站优化排名孝感本地网站优化多少钱济南服务专业网站推广优化信阳网站建设及优化东莞seo优化网站东莞按天网站优化效果如何莆田网站优化如何遵义网站优化平台重庆网站seo优化报价网站优化排名推广联系方式买网站优化专业的网站优化价格优惠网站优化怎么优化网站内容网站的优化是否学香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声卫健委通报少年有偿捐血浆16次猝死汪小菲曝离婚始末何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言男子被猫抓伤后确诊“猫抓病”周杰伦一审败诉网易中国拥有亿元资产的家庭达13.3万户315晚会后胖东来又人满为患了高校汽车撞人致3死16伤 司机系学生张家界的山上“长”满了韩国人?张立群任西安交通大学校长手机成瘾是影响睡眠质量重要因素网友洛杉矶偶遇贾玲“重生之我在北大当嫡校长”单亲妈妈陷入热恋 14岁儿子报警倪萍分享减重40斤方法杨倩无缘巴黎奥运考生莫言也上北大硕士复试名单了许家印被限制高消费奥巴马现身唐宁街 黑色着装引猜测专访95后高颜值猪保姆男孩8年未见母亲被告知被遗忘七年后宇文玥被薅头发捞上岸郑州一火锅店爆改成麻辣烫店西双版纳热带植物园回应蜉蝣大爆发沉迷短剧的人就像掉进了杀猪盘当地回应沈阳致3死车祸车主疑毒驾开除党籍5年后 原水城县长再被查凯特王妃现身!外出购物视频曝光初中生遭15人围殴自卫刺伤3人判无罪事业单位女子向同事水杯投不明物质男子被流浪猫绊倒 投喂者赔24万外国人感慨凌晨的中国很安全路边卖淀粉肠阿姨主动出示声明书胖东来员工每周单休无小长假王树国卸任西安交大校长 师生送别小米汽车超级工厂正式揭幕黑马情侣提车了妈妈回应孩子在校撞护栏坠楼校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变老人退休金被冒领16年 金额超20万西藏招商引资投资者子女可当地高考特朗普无法缴纳4.54亿美元罚金浙江一高校内汽车冲撞行人 多人受伤

深圳坪山网站建设公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化