React 高级教程

在这里插入图片描述


目录

  • 前言
  • setState
  • 函数式编程
  • Hooks
  • My Hooks
  • useState
    • 定义
    • 原理
    • 函数式更新
      • reduce 方法
      • react 源码
  • useEffect
    • 定义
    • 原理
    • 无限循环
  • useCallback
    • 定义
    • 原理
  • useMemo
    • 定义
    • 比较
  • Redux
  • useReducer
    • 定义
    • 使用
    • 应用
  • useContext


前言

在现代前端开发中,React已经成为了一种无法忽视的技术。它的函数式编程模式,以及强大的Hooks API,为我们提供了一种全新的编程范式,使得我们可以更加灵活、高效地构建用户界面。

在这篇文章中,我们将深入探讨React的函数式编程,以及Hooks的定义和原理。我们将详细介绍一些常见的Hooks,如useState、useEffect、useCallback、useMemo、useContext和useReducer等,帮助你更好地理解和使用这些强大的工具。无论你是React的新手,还是有一定经验的开发者,我相信你都能在这篇文章中找到有价值的内容。让我们一起,深入探索React的世界。

setState

setState 本身代码的执行肯定是同步的,这里的异步是指是多个 state 会合成到一起进行批量更新。

函数式编程

这篇文章写的真的太好了,一定要读:简明 JavaScript 函数式编程——入门篇。
总结一下: 函数式编程有两个核心概念。

  • 数据不可变(无副作用): 它要求你所有的数据都是不可变的,这意味着如果你想修改一个对象,那你应该创建一个新的对象用来修改,而不是修改已有的对象。
  • 无状态: 主要是强调对于一个函数,不管你何时运行,它都应该像第一次运行一样,给定相同的输入,给出相同的输出,完全不依赖外部状态的变化。

纯函数带来的意义。

  • 便于测试和优化:这个意义在实际项目开发中意义非常大,由于纯函数对于相同的输入永远会返回相同的结果,因此我们可以轻松断言函数的执行结果,同时也可以保证函数的优化不会影响其他代码的执行。
  • 可缓存性:因为相同的输入总是可以返回相同的输出,因此,我们可以提前缓存函数的执行结果。
  • 更少的 Bug:使用纯函数意味着你的函数中不存在指向不明的 this,不存在对全局变量的引用,不存在对参数的修改,这些共享状态往往是绝大多数 bug 的源头。

Hooks

用动画和实战打开 React Hooks(一):useState 和 useEffect - 掘金
用动画和实战打开 React Hooks(二):自定义 Hook 和 useCallback - 掘金
用动画和实战打开 React Hooks(三):useReducer 和 useContext - 掘金

1.png

2.png

  • Hooks **只能用于 React 函数式组件,**组件的渲染的状态、事件处理函数每一次都是独立的。

My Hooks

function useBodyScrollPosition() {
  const [scrollPosition, setScrollPosition] = useState(null);

  useEffect(() => {
    const handleScroll = () => setScrollPosition(window.scrollY);
    document.addEventListener('scroll', handleScroll);
    return () =>
      document.removeEventListener('scroll', handleScroll);
  }, []);

  return scrollPosition;
}
  • 表面上:一个命名格式为 useXXX 的函数,但不是 React 函数式组件
  • 本质上:内部通过使用 React 自带的一些 Hook (例如 useState 和 useEffect )来实现某些通用的逻辑
  • 推荐的库:React Use 、aHooks、Umi Hooks

useState

定义

const [state, setState] = useState(initialValue);

其中 state 就是一个状态变量,setState 是一个用于修改状态的 Setter 函数,而 initialValue 则是状态的初始值

原理

1.png

  1. 在初次渲染时,我们通过 useState 定义了多个状态;
  2. 每调用一次 useState ,都会在组件之外生成一条 Hook 记录,同时包括状态值(用 useState 给定的初始值初始化)和修改状态的 Setter 函数;
  3. 多次调用 useState 生成的 Hook 记录形成了一条链表
  4. 触发 onClick 回调函数,调用 setS2 函数修改 s2 的状态,不仅修改了 Hook 记录中的状态值,还即将触发重渲染

函数式更新

reduce 方法

const nums = [1, 2, 3]
const value = nums.reduce((acc, next) => acc + next, 0)
  • next 是遍历数组nums的值,acc默认值自定义,新的值是函数的返回值
  • 特点是只返回一个值,不修改输入值

react 源码

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

1.png

2.png

  • 详细实现可以看链接文章的动态图
  • 静态更新值直接返回结果
  • 函数更新值会先把当前数据状态传入函数并计算结果返回

useEffect

定义

useEffect(() => {
  const intervalId = setInterval(doSomething(), 1000);
  return () => clearInterval(intervalId);
});
  • effectFn 是一个执行某些可能具有副作用的 Effect 函数(例如数据获取、设置/销毁定时器等),它可以返回一个清理函数(Cleanup),例如大家所熟悉的 setInterval 和 clearInterval
    • 每个 Effect 必然在渲染之后执行,因此不会阻塞渲染,提高了性能
    • 在运行每个 Effect 之前,运行前一次渲染的 Effect Cleanup 函数(如果有的话)
    • 当组件销毁时,运行最后一次 Effect 的 Cleanup 函数
  • 依赖数组选项:
    • 不写,每一次渲染后执行
    • [],只会在组件初次渲染执行
    • [a,b]会在依赖项发生变化执行
    • 判断数据是否发生改变使用 Object.is,对于基本数据类型可以直接判断(和===相似,不同点在于NAN为true,0和-0为false),但对于对象类型就判断在堆内存的引用地址是否发生改变

原理

1.png

  1. useState 和 useEffect 在每次调用时都被添加到 Hook 链表中;
  2. useEffect 还会额外地在一个队列中添加一个等待执行的 Effect 函数;
  3. 在渲染完成后,依次调用 Effect 队列中的每一个 Effect 函数。

无限循环

  • 依赖项在事件的内部更新,导致触发渲染 => 触发 Effect => 修改状态 => 触发重渲染的无限循环
  • 要正确传递依赖项,特别是被useState 定义和引用的数据类型

useCallback

定义

const memoizedCallback = useCallback(callback, deps);
  • useCallback 是一个允许你在多次渲染中缓存函数的 React Hook。
  • 第一个参数 callback 就是需要记忆的函数,第二个参数就是大家熟悉的 deps 参数
  • 在 Memoization 的上下文中,这个 deps 的作用相当于缓存中的键(Key),如果键没有改变,那么就直接返回缓存中的函数,如果有改变,就生成新的函数并缓存
  • 在大多数情况下,我们都是传入空数组 [] 作为 deps 参数,这样 useCallback 返回的就始终是同一个函数,永远不会更新

原理

1.png

2.png

  • 组件状态更新或者props改变会导致组件重新渲染,如果需要传递函数给子组件,那么一般的函数每次就会定义新的函数,导致子组件渲染(无法使用 memo 跳过)
  • 引用数据类型函数永远指向相同的堆内存地址,可以保证函数在初始化定义之后就不改变

useMemo

定义

const cachedValue = useMemo(calculateValue, dependencies)
  • useMemo 是一个 React Hook,它在每次重新渲染的时候能够缓存计算的结果

比较

  • useMemo 用于缓存结果,useCallback用于缓存值
function useCallback(fn, dependencies) {
  return useMemo(() => fn, dependencies);
}

Redux

1.png
堪称 React 版本的 Pinia,这才是你该选的 React 状态管理库! - 掘金

  • redux 是通过全局的状态管理来实现数据的通信
  • 和之前使用的 vuex 差不多,但现在有更好的状态管理库可以使用

useReducer

定义

const [state, dispatch] = useReducer(reducer, initialArg, init);
  1. 第一个参数 reducer 显然是必须的,它的形式跟 Redux 中的 Reducer 函数完全一致,即 (state, action) => newState。
  2. 第二个参数 initialArg 就是状态的初始值。
  3. 第三个参数 init 是一个可选的用于懒初始化(Lazy Initialization)的函数,这个函数返回初始化后的状态。

使用

// Reducer 函数
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
    </>
  );
}
  • 定义函数和初始状态,获取 state 和 dispatch 函数
  • 通过传入参数(带上类型),在reducer函数中修改并返回新的值

应用

  • 简单的状态修改更新 useState 够用
  • 对于需要维护的状态本身比较复杂,多个状态之间相互依赖、修改状态的过程比较复杂可以使用
  • 例子如下:
// 用于懒初始化的函数
function init(initialState) {
  return {
    past: [],
    present: initialState,
    future: [],
  };
}

// Reducer 函数
function reducer(state, action) {
  const { past, future, present } = state;
  switch (action.type) {
    case 'UNDO':
      return {
        past: past.slice(0, past.length - 1),
        present: past[past.length - 1],
        future: [present, ...future],
      };
    case 'REDO':
      return {
        past: [...past, present],
        present: future[0],
        future: future.slice(1),
      };
    default:
      return state;
  }
}

useContext

使用 Context 深层传递参数 – React 中文文档

1.png

  • Context 使组件向其下方的整个树提供信息,会穿过中间的任何组件
  • 通过 useContext ,我们就可以轻松地让所有组件都能获取到 dispatch 函数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/150857.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java —— 多态

目录 1. 多态的概念 2. 多态实现条件 3. 重写 重写与重载的区别 4. 向上转型和向下转型 4.1 向上转型 4.2 向下转型 5. 多态的优缺点 6. 避免在构造方法中调用重写的方法 我们从字面上看"多态"两个字, 多态就是有多种状态/形态. 比如一个人可以有多种状态, …

基于STM32的无线通信系统设计与实现

【引言】 随着物联网的迅速发展&#xff0c;无线通信技术逐渐成为现代通信领域的关键技术之一。STM32作为一款广受欢迎的微控制器&#xff0c;具有丰富的外设资源和强大的计算能力&#xff0c;在无线通信系统设计中具有广泛的应用。本文将介绍如何基于STM32实现一个简单的无线通…

Go ZIP压缩文件读写操作

创建zip文件 golang提供了archive/zip包来处理zip压缩文件&#xff0c;下面通过一个简单的示例来展示golang如何创建zip压缩文件&#xff1a; func createZip(filename string) {// 缓存压缩文件内容buf : new(bytes.Buffer)// 创建zipwriter : zip.NewWriter(buf)defer writ…

Oracle OCP / MySQL OCP认证容易通过吗

诸多学员在首次考OCP时&#xff0c;不清楚要如何选择。在本文中&#xff0c;我会为大家进行讲解&#xff01; 选择OCP认证时需要考虑的几大项目&#xff1a; 授课老师师资经验 课程大纲 试听课程 考试通过率 业界口碑 服务质量 郭一军老师的OCP培训在业界培训的学员中已…

3ds Max渲染用专业显卡还是游戏显卡?

使用3dsmax建模时&#xff0c;会面临诸多选择&#xff0c;除了用vr还是cr的决策&#xff0c;硬件选择上也存在着疑问&#xff0c;比如用专业显卡还是消费级游戏显卡&#xff1f;一般来说&#xff0c;除非是特别专业的大型项目和软件&#xff0c;且预算在5位数以上&#xff0c;常…

【MySql】12- 实践篇(十)

文章目录 1. 为什么临时表可以重名?1.1 临时表的特性1.2 临时表的应用1.3 为什么临时表可以重名&#xff1f;1.4 临时表和主备复制 2. MySql内部临时表使用场景2.1 union 执行流程2.2 group by 执行流程2.3 group by 优化方法 -- 索引2.4 group by 优化方法 -- 直接排序 3. Me…

软件开发之路——关于架构师的一些书籍

文章目录 &#x1f4cb;前言&#x1f3af;什么是架构师&#x1f525;文末送书《高并发架构实战&#xff1a;从需求分析到系统设计》《中台架构与实现&#xff1a;基于DDD和微服务》《架构师的自我修炼&#xff1a;技术、架构和未来》《分布式系统架构&#xff1a;架构策略与难题…

第三章 栈和队列【24王道数据结构笔记】

1.栈 1.1 栈的基本概念 只允许在一端(栈顶top)进行插入或删除操作的受限的线性表。后进先出&#xff08;Last In First Out&#xff09;LIFO。或者说先进后出FILO。 进栈顺序&#xff1a;a1 > a2 > a3 > a4 > a5出栈顺序&#xff1a;a5 > a4 > a3 > a2 …

GB/T 1032-2023 三相异步电机试验方法 笔记

仅仅是为了技术分享。如有侵权请随时告知&#xff0c;我会尽快删除相关内容&#xff0c;谢谢&#xff01; 1.阻值的温度效应 7.x 2.温升与负载电 7.x 3.力矩修正公式及功率公式 8.3 3.1铁损和铜损测量 4.空载特性曲线 9.3 4.1 空载损耗 5.堵转特性 6.剩余损耗 6.1 另一种由转子…

系列一、JVM的架构图

一、JVM的位置 JVM是运行在操作系统之上的&#xff0c;它与硬件没有直接的交互。 二、JVM的架构图

Leadshop开源商城小程序源码 – 支持公众号H5

Leadshop是一款出色的开源电商系统&#xff0c;具备轻量级、高性能的特点&#xff0c;并提供持续更新和迭代服务。该系统采用前后端分离架构&#xff08;uniappyii2.0&#xff09;&#xff0c;以实现最佳用户体验为目标。 前端部分采用了uni-app、ES6、Vue、Vuex、Vue Router、…

算法萌新闯力扣:存在重复元素II

力扣题&#xff1a;存在重复元素II 开篇 这道题是217.存在重复元素的升级版&#xff0c;难度稍微提高。通过这道题&#xff0c;能加强对哈希表和滑动窗口的运用。 题目链接:219.存在重复元素II 题目描述 代码思路 1.利用哈希表&#xff0c;来保存数组元素及其索引位置 2.遍…

STL—next_permutation函数

目录 1.next_permutation函数的定义 2.简单使用 2.1普通数组全排列 2.2结构体全排列 2.3string 3.补充 1.next_permutation函数的定义 next_permutation函数会按照字母表顺序生成给定序列的下一个较大的排列&#xff0c;直到整个序列为降序为止。与其相对的还有一个函数—…

Linux在线安装MySQL8.0.24安装、MySQL数据备份和恢复

一、 Linux在线安装MySQL8.0.24 如果机器上已经有MySQL5.7版本需要先卸载 首先&#xff0c;需要停止MySQL服务。可以通过以下命令来停止服务&#xff1a; sudo systemctl stop mysqld接下来&#xff0c;我们需要卸载MySQL5.7。可以通过以下命令来卸载&#xff1a; sudo yum…

《红蓝攻防对抗实战》十三.内网穿透之利用HTTP协议进行隧道穿透

内网穿透之利用HTTP协议进行隧道穿透 一.前言二.前文推荐三.利用HTTP协议进行隧道穿透1. Reduh进行端口转发2. ReGeorg进行隧道穿透3. Neo-reGeorg加密隧道穿透4. Tunna进行隧道穿透5 .Abptts加密隧道穿透6. Pivotnacci加密隧道穿透 四.本篇总结 一.前言 本文介绍了利用HTTP协…

操作符——C语言初阶

一.算数操作符&#xff1a; - * / % 、-、*、/这四个运算符均可用于整数及浮点数的运算。 当使用/运算符时&#xff0c;如果两个操作数均为整型&#xff0c;那么执行整数除法&#xff0c;运算结果也为整型&#xff1b;如果两个操作数至少一个为浮…

AJAX入门Day01笔记

Day01_Ajax入门 知识点自测 如下对象取值的方式哪个正确? let obj {name: 黑马 }A: obj.a B: obj()a 答案 A选项正确 哪个赋值会让浏览器解析成标签显示? let ul document.querySelector(#ul) let str <span>我是span标签</span>A: ul.innerText str B: ul…

<MySQL> 查询数据进阶操作 -- 联合查询

目录 一、什么是笛卡尔积&#xff1f; 二、什么是联合查询&#xff1f; 三、内连接 3.1 简介 3.2 语法 3.3 更多的表 3.4 操作演示 四、外连接 4.1 简介 4.2 语法 4.3 操作演示 五、自连接 5.1 简介 5.2 自连接非必要不使用 六、子查询(嵌套查询) 6.1 简介 6.…

计算机毕设 深度学习 大数据 股票预测系统 - python lstm

文章目录 0 前言1 课题意义1.1 股票预测主流方法 2 什么是LSTM2.1 循环神经网络2.1 LSTM诞生 2 如何用LSTM做股票预测2.1 算法构建流程2.2 部分代码 3 实现效果3.1 数据3.2 预测结果项目运行展示开发环境数据获取 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要…

自己动手实现一个深度学习算法——六、与学习相关的技巧

文章目录 1.参数的更新1&#xff09;SGD2&#xff09;Momentum3&#xff09;AdaGrad4&#xff09;Adam5&#xff09;最优化方法的比较6&#xff09;基于MNIST数据集的更新方法的比较 2.权重的初始值1&#xff09;权重初始值不能为02&#xff09;隐藏层的激活值的分布3&#xff…