React Hook 到底是个啥?

React Hook 系列(一):彻底搞懂react-hooks 用法(万字慎点) 用心阅读,跟随codesandbox demo或运行源码,你将熟悉react各种组件的优缺点及用法,彻底熟悉react hook的用法,收益应该不小 大纲: react 不同组件用法。 react hook 相比以前带来什么。 react hook 的用法。 React 组件的发展 1. 功能(无状态)组件 Functional (Stateless) Compone... 阅读详情

本篇文章参考以下博文

前言

  最近在和同事们交流的时候,发现大家对 hook 的理解是,这玩意就是生命周期,原来放在生命周期里的东西,现在都要放到 hook 里。

  如果刚接触 hook 的话,那么这个解释可以帮助你快速明白 hook 的用法,但是往深了说, hook 与生命周期还是有一定区别的。今天咱们就来研究研究,区别在哪?

  阅读本节需要对 react 的 fiber 结构有一定的了解。

举个例子

  我们举一个形象一点的例子,让大家先有一个概念。比如下图:
在这里插入图片描述

   react 的图标大家都很熟悉了哈,这个图标的含义是原子,中间的是原子核,外面的轨迹是飞行的核外电子。那么 hook 的概念,就是像是电子。

自己实现 useState

  接下来我们自己实现一个最常用的 hook useState 。

  首先过程很简单,大家先别害怕。看下面一个例子

function App() {
  const [num, updateNum] = useState(0);

  return <p onClick={() => updateNum(num => num + 1)}>{num}</p>;
}

  上面是一个简单的函数组件,一个按钮,点击之后会对 num 进行累加。那么这个组件中,涉及 useState 的工作有两部分:

  1. 通过一些途径产生更新,更新会造成组件 render 。

  2. 组件 render 时 useState 返回的 num 为更新后的结果。

  上面第一步的过程,又可以分解为:

  1. 调用 ReactDOM.render 会产生 mount 的更新,更新内容为 useState 的 initialValue (即0)。

  2. 点击 p 标签触发 updateNum 会产生一次 update 的更新,更新内容为 num => num + 1 。

  接下来我们研究下,这两步是怎么实现的。

  页面产生 更新 后,组件 render ,那么这个 更新 是什么?源码里这个更新是一个链表的节点,

const update = {
  // 更新执行的函数(num => num + 1)
  action,
  // 与同一个Hook的其他更新形成链表
  next: null
}

  这些更新节点被放在了一个环装单向链表里,类似如下结构:
在这里插入图片描述

  调用 updateNum 的过程,执行 dispatchAction 函数。

function dispatchAction(queue, action) {
  // 创建update
  const update = {
    action,
    next: null
  }

  // 环状单向链表操作
  if (queue.pending === null) { //链表为空时
    update.next = update;
  } else {  //不为空时
    update.next = queue.pending.next;
    queue.pending.next = update;
  }
  queue.pending = update;

  // 模拟React开始调度更新
  schedule();
}

  上面逻辑的效果是 queue.pending 始终指向最后一个插入的 update 。

  这样做的好处是,当我们要遍历 update 时, queue.pending.next 指向第一个插入的 update 。

在这里插入图片描述

状态保存

  知道了 update 的逻辑之后,我们来看看状态是怎么保存在 queue 里面的。我们知道 ClassComponent 的状态是保存在属性 state 里面的。而 FunctionComponent 的状态是保存在 fiber 里面的,类似下面:

// App组件对应的fiber对象
const fiber = {
  // 保存该FunctionComponent对应的Hooks链表
  memoizedState: null,
  // 指向App函数
  stateNode: App
};

Hook 数据结构

  接下来我们关注 fiber.memoizedState 中保存的 Hook 的数据结构。

hook = {
  // 保存update的queue,即上文介绍的queue
  queue: {
    pending: null
  },
  // 保存hook对应的state
  memoizedState: initialState,
  // 与下一个Hook连接形成单向无环链表
  next: null
}

  可以看到, Hook 与 update 类似,都通过链表连接。不过 Hook 是无环的单向链表。

  注意区分 update 与 hook 的所属关系:

  每个 useState 对应一个 hook 对象。

  调用 const [num, updateNum] = useState(0) ;时 updateNum (即上文介绍的 dispatchAction )产生的 update 保存在 useState 对应的 hook.queue 中。

模拟React调度更新流程

  在上文 dispatchAction 末尾我们通过 schedule 方法模拟 React 调度更新流程。

function dispatchAction(queue, action) {
  // ...创建update
  
  // ...环状单向链表操作

  // 模拟React开始调度更新
  schedule();
}

  现在我们来实现他。

  我们用 isMount 变量指代是 mount 还是 update 。(源码中对于 mount 和 update 的处理是分开的,这里用一个 isMount 简化了)

// 首次render时是mount
isMount = true;

function schedule() {
  // 更新前将workInProgressHook重置为fiber保存的第一个Hook
  workInProgressHook = fiber.memoizedState;
  // 触发组件render
  fiber.stateNode();
  // 组件首次render为mount,以后再触发的更新为update
  isMount = false;
}

  通过 workInProgressHook 变量指向当前正在工作的 hook 。

workInProgressHook = fiber.memoizedState;

  在组件 render 时,每当遇到下一个 useState ,我们移动 workInProgressHook 的指针。

workInProgressHook = workInProgressHook.next;

  这样,只要每次组件 render 时 useState 的调用顺序及数量保持一致,那么始终可以通过 workInProgressHook 找到当前 useState 对应的 hook 对象。

  到这里第一步就完成了,接下来我们进行第二步。即组件 render 时 useState 返回的 num 为更新后的结果。

计算 State

  组件 render 时会调用 useState ,他的大体逻辑如下:

function useState(initialState) {
  // 当前useState使用的hook会被赋值该该变量
  let hook;

  if (isMount) {
    // ...mount时需要生成hook对象
  } else {
    // ...update时从workInProgressHook中取出该useState对应的hook
  }

  let baseState = hook.memoizedState;
  if (hook.queue.pending) {
    // ...根据queue.pending中保存的update更新state
  }
  hook.memoizedState = baseState;

  return [baseState, dispatchAction.bind(null, hook.queue)];
}

  首先我们需要先关注以下如何获取 hook 对象:

if (isMount) {
  // mount时为该useState生成hook
  hook = {
    queue: {
      pending: null
    },
    memoizedState: initialState,
    next: null
  }

  // 将hook插入fiber.memoizedState链表末尾
  if (!fiber.memoizedState) {
    fiber.memoizedState = hook;
  } else {
    workInProgressHook.next = hook;
  }
  // 移动workInProgressHook指针
  workInProgressHook = hook;
} else {
  // update时找到对应hook
  hook = workInProgressHook;
  // 移动workInProgressHook指针
  workInProgressHook = workInProgressHook.next;
}

  当找到该 useState 对应的 hook 后,如果该 hook.queue.pending 不为空(即存在 update ),则更新其 state 。

// update执行前的初始state
let baseState = hook.memoizedState;

if (hook.queue.pending) {
  // 获取update环状单向链表中第一个update
  let firstUpdate = hook.queue.pending.next;

  do {
    // 执行update action
    const action = firstUpdate.action;
    baseState = action(baseState);
    firstUpdate = firstUpdate.next;

    // 最后一个update执行完后跳出循环
  } while (firstUpdate !== hook.queue.pending.next)

  // 清空queue.pending
  hook.queue.pending = null;
}

// 将update action执行完后的state作为memoizedState
hook.memoizedState = baseState;

  完整的过程如下:

function useState(initialState) {
  let hook;

  if (isMount) {
    hook = {
      queue: {
        pending: null
      },
      memoizedState: initialState,
      next: null
    }
    if (!fiber.memoizedState) {
      fiber.memoizedState = hook;
    } else {
      workInProgressHook.next = hook;
    }
    workInProgressHook = hook;
  } else {
    hook = workInProgressHook;
    workInProgressHook = workInProgressHook.next;
  }

  let baseState = hook.memoizedState;
  if (hook.queue.pending) {
    let firstUpdate = hook.queue.pending.next;

    do {
      const action = firstUpdate.action;
      baseState = action(baseState);
      firstUpdate = firstUpdate.next;
    } while (firstUpdate !== hook.queue.pending)

    hook.queue.pending = null;
  }
  hook.memoizedState = baseState;

  return [baseState, dispatchAction.bind(null, hook.queue)];
}

  到此为止,我们完整的实现了一个 hook ,它与源码中的 hook 还是有细微差异的,但是原理相同。

  最后点以下题,看到现在大家应该感觉出来 hook 和生命周期还是很不一样的吧,那各位觉得 hook 到底是个啥?

  我个人感觉更像是一个工具,这个工具会帮我们把数据更新到页面上,不同的 hook 更新效果不太相同,有的会同步更新,有的则会延迟更新,我们要做的则是在不同的业务需要下,使用这些工具,至于工具到底是怎么做到的,而且还做的这么好,那就需要我们反复的研究源码,才能熟知。




【React Hooks详解】由浅入深从理解到自己封装一个Hook 本文将由浅入深探讨React Hooks的使用,并指导你如何自定义封装Hooks,以进一步提升开发效率和代码质量。 阅读详情

相关推荐

【React】React 内置 Hook

React 内置 Hook 是一组允许你在函数组件中使用 state 和其他 React 特性的函数。它们极大地扩展了函数组件的功能,使得在无需编写 class 的情况下也能使用 React 的全部功能

weixin_42286461的博客 1439

react hook 详解及使用

1、hooks 是什么 Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React。 2、为什么要使用 hooks 难以理解的 class 、组件中必须去理解 javascript 与 this 的工作方式、需要绑定事件处理器、纯函数组件

xuewenjie0217的博客 2万+

React Hook实战

一、 Hook 简介 1.1 Hook历史 在React Hook出现之前的版本中,组件主要分为两种:函数式组件和类组件。其中,函数式组件通常只考虑负责UI的渲染,没有自身的状态也没有业务逻辑代码,是一个纯函数。而类组件则不同,类组件有自己的内部状态,界面的显示结果通常由props 和 state 决定,因此它也不再那么纯洁。函数式组件,类组件有如下一些缺点: 状态逻辑难以复用。在类组件中,为了重用某些状态逻辑,社区提出了render props 或者 hoc 等方案,但是这些方案对组件的侵入性太强,并且

xiangzhihong8的专栏 740

React Hooks详解

React的函数式组件式本身是没有状态的和其他类似于class组件的功能,所以一开始,函数组件一般只作为容器组件存在,用来展示父级组件传入的值。而16.8之后出现的 hooks(钩子),打开了函数式组件的新大门。 useState 作用:用来记录函数式组件的状态。 使用方式: import React, { useState } from 'react' const [n, setN] = React.useState(0) 例子: import React, {useState} from

duansamve的博客 6332

Oracle到金仓数据库信创改造迁移实施规划方案

**性能测试和优化**:对金仓数据库的性能进行测试,根据业务负载情况进行必要的调优,确保系统能够稳定高效运行。- **数据兼容性**:评估Oracle数据库中的数据结构和金仓数据库的兼容性,明确需要重构的数据模型。- **性能测试**:通过对金仓数据库的性能测试,预估在实际业务环境下的表现,是否能达到业务需求。- **工具选择**:选择适合的迁移工具,如金仓数据库提供的迁移工具,能够提升迁移效率和准确性。- **全面迁移**:在初步迁移成功后,进行全面数据迁移,确保所有数据完整迁移到金仓数据库上。

hdrhdrjdididrr的博客 480

Isaac Gym摄像头数据获取全攻略:从CPU到GPU,教你实时显示RGB与深度图

本文详细介绍了在Isaac Gym中获取摄像头数据的两种高效方案:CPU模式与GPU张量模式。通过实战代码示例,展示了从摄像头配置、数据获取到实时可视化RGB与深度图的全流程,帮助开发者优化机器人仿真与计算机视觉应用的性能。特别强调了GPU模式下的零拷贝访问与张量运算优势,适用于需要低延迟处理的场景。

weixin_29056701的博客 387

React Hook用法详解(6个常见hook)

PS:class组件中this.setState更新是state是合并, useState中setState是替换。

Addisoni 2779

EXCEL实现分层自定义比例随机抽样(图+文教程)

EXCEL实现分层自定义比例随机抽样(图+文教程) 单一字段分层自定义比例随机抽样 多字段分层自定义比例随机抽样 单一字段分层自定义比例随机抽样 首先数据源如下,我们想随机抽张三的金额数据10%、李四金额20%、王五5%、哈哈15%、李六10% 首先第一步,添加辅助列,随机数 =RAND() 对数据进行高级排序 升序、降序都可以 添加辅助列...

可乐联盟 2万+

react的hook总结

React Hooks 提供了一种在函数组件中使用状态、上下文、副作用等功能的方式。

qq_44693497的博客 1183

iPhone免越狱Git服务器搭建教程-iSH

iPhone免越狱Git服务器搭建教程

jts666的博客 4427

避坑指南:STM32H7不同DMA控制器(MDMA/DMA2D/BDMA)到底该用哪个?

本文深入解析STM32H7系列芯片的DMA控制器选型策略,涵盖MDMA、DMA2D、BDMA等不同控制器的架构原理与性能对比。通过实际项目案例,提供高速TCM数据搬运、GUI加速、低功耗传输等场景的选型决策树,并分享性能优化与调试技巧,帮助工程师避开常见陷阱,提升系统效率。

weixin_26876073的博客 447

视频教程-React hook 实战【作业+传授经验】-ReactJS

React hook 实战【作业+传授经验】 晟暄科技CEO,HTML5 &...

weixin_28740045的博客 582

GaussDB本地安装手册(主备模式)

如果实例状态是Normal,则安装成功。三节点集中式配置文件。

Sebastien23的博客 2633

React hook 10种 Hook (详细介绍及使用)

React Hook是什么? React官网是这么介绍的: Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 完全可选的 你无需重写任何已有代码就可以在一些组件中尝试 Hook。但是如果你不想,你不必现在就去学习或使用 Hook。 100% 向后兼容的 Hook 不包含任何破坏性改动。 现在可用 H...

@baby张~的博客 1万+

Android 12 大屏时底下显示任务栏以及虚拟按键靠右问题

Android 12 点大屏时,底下导航栏变成显示任务栏,虚拟按键靠右的分析以及修改

Android系统开发笔记 4686

n8n智能体开发:Microsoft Outlook 节点

使用 Microsoft Outlook 节点可以自动化 Microsoft Outlook 工作流程,并将其与其他应用程序集成。n8n 内置支持多种 Microsoft Outlook 功能,包括创建、更新、删除和获取文件夹、邮件及草稿等操作。

王国平的博客 570

全面解析 React Hook

React Hook是React 16.8引入的特性,允许函数组件使用状态、生命周期等能力,解决了类组件状态逻辑复用困难、代码组织混乱等问题。核心Hook包括useState(状态管理)、useEffect(副作用处理)和useContext(上下文共享)。使用Hook需遵循两条规则:只在顶层和React函数中调用。自定义Hook可提取复用逻辑,比高阶组件更简洁。相比类组件,Hook提供了更直观的代码组织和更低的入门门槛,是React开发的未来趋势。

前端技术的学习整理 1374

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

视频教程-「ONE-DEMO」React hook 时间轴跨度组件-ReactJS

「ONE-DEMO」React hook 时间轴跨度组件 晟暄科技CEO,H...

weixin_34213147的博客 296

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

React之Hook

1.Hook可以使你在无需修改组件结构的情况下,复用状态逻辑;

weixin_43794803的博客 212

React Hook

1. Hook 简介 Hook 可以让我们在不编写 class 的情况下使用 state 以及其他的 React 特性。 1.1 没有破坏性改动 Hook是: 完全可选的。无需重写任何已有代码就可以在一些组件中尝试Hook。 100%向后兼容。Hook不包含任何破坏性改动。 使用Hook 的原因: 可以使用 Hook 从组件中提取状态逻辑,使得这些逻辑可以单独测试并复用。Hook 使你在无需修改组件结构的情况下复用状态逻辑。 这使得在组件间或社区内共享 Hook 变得更便捷。 Hook 将组件中

weixin_43552533的博客 333

React的hook✅

这是为了确保每次组件渲染时,Hooks 的调用顺序保持一致。React。每当一个函数组件被渲染时,所有的 hook 调用都是按照从上到下的顺序依次执行的。React 内部会维护一个状态列表,这个列表中的每个状态项都对应一个 hook 的调用,包括 useState、useEffect 等。当你调用 useState(initialValue) 时,React 会在内部为这个状态分配一个索引。该索引基于 hook 调用的顺序。例如,。Q:既然每次视图的更新都会重新执行整个函数,那必然会执行到这句代码。

YUYUYU972的博客 1030

React中Hook的使用

1.什么是Hook? Hook是React 16.8的新增属性。可以在不编写calss的情况下使用state以及其他的React特性 2.Hook优势? 其主要是为了解决一下几个常见问题: 在组件之间服用状态逻辑难 复杂组件变的难以理解 class学习及js中this的工作方式 简化周期函数,避免重复代码 … Hook可以让我们无需学习浮躁的函数式和响应式编程,同时也遵循React的精神原则。...

WCBandCTZ的博客 2058

03-React-Hook

Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用。

zhangjun133133的博客 1130

React hook 10种 Hook

React Hook是什么? React官网是这么介绍的: Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 完全可选的 你无需重写任何已有代码就可以在一些组件中尝试 Hook。但是如果你不想,你不必现在就去学习或使用 Hook。 100% 向后兼容的 Hook 不包含任何破坏性改动。 现在可用 Hook 已发布于 v16.8.0。 没有计划从 React 中移除 class 你可以在本页底部的章节读到更多关于

weixin_45573779的博客 612

React中一些常用的Hook

Hook 官方解释:*Hook* 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React。 注:Hook 是 React 16.8 的新增的,使用时需要注意更新版本。 特点: 渐进式,没有破坏性改动,使用的组件完全可以自由选择,100%兼容其

weixin_53533170的博客 1498

react中关于hook介绍及其使用

前言 最近由于公司的项目开发,就学习了在react关于hook的使用,对其有个基本的认识以及如何在项目中去应用hook。在这篇博客中主要从以下的几个点进行介绍: hook简介 hook中常用api的使用 hook在使用过程中需要去注意的地方 hook中怎样去实现class组件中的声明周期函数 hook 首先介绍关于hook1的含义,以及其所要去面对的一些场景 含义:Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。简

domino~~的博客 4322
上一篇: Webpack常用的压缩,CSS,JS,图片
下一篇: React-router源码—好家伙!
不见浅诗~
博客等级 码龄7年 506粉丝 129原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值