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 函数

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ESP32网络开发实例-将数据保存到InfluxDB时序数据库

将数据保存到InfluxDB时序数据库 文章目录 将数据保存到InfluxDB时序数据库1、InfluxDB介绍与安装3、软件准备4、硬件准备5、代码实现6、InfluxDB数据可视化在本文中,将介绍 InfluxDB 以及如何将其与 ESP32 开发板一起使用。 我们将向展示如何创建数据库桶并将 ESP32 数据发送…

探索人工智能领域——每日30个名词详解【day3】

目录 前言 正文 总结 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filotimo__✍️原创&#xff0c;首发于CSDN&#x1f4da;。 &#x1f4e3;如需转载&#xff0c;请事先与我联系以…

C++ Qt 学习(六):Qt http 编程

1. http 基础 HTTP 基础教程C Web 框架 drogonoatpp 2. C Qt 用户登录、注册功能实现 login_register.h #pragma once#include <QtWidgets/QDialog> #include "ui_login_register.h" #include <QNetworkReply>class login_register : public QDialog…

Peoeasy机器人:原点无法重置问题

机械手在伺服关闭的模式下&#xff0c;插入定位插销&#xff0c;进入机构设定重置原点&#xff0c;发现PUU值没有变化 问题原因 台达软件版本比较多&#xff0c;每个版本重置原点的模式和马达偏差角的默认值是有一定差异的。再重置原点之前尽可能先确认一下重置原点的模式和马…

云服务器如何选?腾讯云2核2G3M云服务器88元一年!

作为一名程序员&#xff0c;在选择云服务器时&#xff0c;我们需要关注几个要点&#xff1a;网络稳定性、价格以及云服务商的规模。这些要素将直接影响到我们的使用体验和成本效益。接下来&#xff0c;我将为大家推荐一款性价比较高的轻应用云服务器。 腾讯云双11活动 腾讯云…

【计算思维】少儿编程蓝桥杯青少组计算思维题考试真题及解析B

STEMA考试-计算思维-U8级(样题) 1.浩浩的左⼿边是&#xff08; &#xff09;。 A.兰兰 B.⻉⻉ C.⻘⻘ D.浩浩 2.2时30分&#xff0c;钟⾯上时针和分针形成的⻆是什么⻆&#xff1f;&#xff08; &#xff09; A.钝⻆ B.锐⻆ C.直⻆ D.平⻆ 3.下⾯是⼀年级同学最喜欢的《⻄游记》…

SystemVerilog学习 (5)——接口

一、概述 验证一个设计需要经过几个步骤&#xff1a; 生成输入激励捕获输出响应决定对错和衡量进度 但是&#xff0c;我们首先需要一个合适的测试平台&#xff0c;并将它连接到设计上。 测试平台包裹着设计,发送激励并且捕获设计的输出。测试平台组成了设计周围的“真实世界”,…

c语言从入门到实战——数组指针与函数指针

数组指针与函数指针 前言1. 字符指针变量2. 数组指针变量2.1 数组指针变量是什么&#xff1f;2.2 数组指针变量怎么初始化? 3. 二维数组传参的本质4. 函数指针变量4.1 函数指针变量的创建4.2 函数指针变量的使用4.3 两段有趣的代码4.3.1 typedef关键字 5. 函数指针数组6. 转移…

VScode+python开发,多个解释器切换问题

内容&#xff1a;主要VScode使用多个解释器 环境准备 VScode编辑器&#xff0c;两个版本python解释器 python3.7.2 python3.11.6 问题&#xff1a; 目前我们的电脑安装了python3.7.2、python3.11.6两个解释器&#xff0c;在vscode编辑器中&#xff0c;无法切换解释器使用如…

泛微E9,独立选择框对应数据库表查询

泛微E9&#xff0c;独立选择框对应数据库表查询 文章目录 泛微E9&#xff0c;独立选择框对应数据库表查询步骤一&#xff1a;准备姓名、姓名文本字段&#xff1a;步骤二&#xff1a;获取选择框字段的id&#xff1a;其他 需求描述&#xff1a;假如流程表单有两个字段&#xff0c…

SpringBoot和Spring源码下载

1.下载&#xff1a;在一个空的干净地创建一个文件夹叫springsourcecode&#xff0c;其实叫什么都行的。 git clone https://github.com/spring-projects/spring-framework.git 2.JDK要和gradle匹配 我们要21的&#xff0c;今天为止2023年11月13日&#xff0c;idea是2023.2。 …

ChatGLM3-6B:新一代开源双语对话语言模型,流畅对话与低部署门槛再升级

项目设计集合&#xff08;人工智能方向&#xff09;&#xff1a;助力新人快速实战掌握技能、自主完成项目设计升级&#xff0c;提升自身的硬实力&#xff08;不仅限NLP、知识图谱、计算机视觉等领域&#xff09;&#xff1a;汇总有意义的项目设计集合&#xff0c;助力新人快速实…

PM2学习

目录 PM2简介 pm2的主要特性 PM2安装 启动PM2项目 查看应用列表&#xff08;查看当前机器执行的所有进程&#xff09; 查看某个应用详情 重启 停止 删除 日志查看 负载均衡 监控CPU/内存 内存使用超过上限自动重启 监听代码变化/自动重启 PM2简介 PM2是常用的node…

虹科示波器 | 汽车免拆检修 | 2014款保时捷卡宴车行驶中发动机偶尔自动熄火

一、故障现象 一辆2014款保时捷卡宴车&#xff0c;搭载4.8L自然吸气发动机&#xff0c;累计行驶里程约为10.3万km。车主反映&#xff0c;行驶中发动机偶尔自动熄火&#xff0c;尤其在减速至停车的过程中故障容易出现。 二、故障诊断 接车后路试&#xff0c;确认故障现象与车主所…

tcpdump wireshark简单使用

tcpdump工作原理 tcpdump 是 Linux 系统中非常有用的网络工具&#xff0c;运行在用户态&#xff0c;本质上是通过调用 libpcap 库的各种 api 来实现数据包的抓取功能&#xff0c;利用内核中的 AF_PACKET 套接字&#xff0c;抓取网络接口中传输的网络包。查 看 tcpdump 的 手册…

《网络协议》06. HTTP 补充 · HTTPS · SSL/TLS

title: 《网络协议》06. HTTP 补充 HTTPS SSL/TLS date: 2022-10-06 18:09:55 updated: 2023-11-15 07:53:52 categories: 学习记录&#xff1a;网络协议 excerpt: HTTP/1.1 协议的不足、HTTP/2、HTTP/3、HTTP 协议的安全问题、SPDY、HTTPS、SSL/TLS、OpenSSL。 comments: fa…

2023年09月 Python(五级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 阅读以下代码,程序输出结果正确的选项是?( ) def process_keywords(keywords_list):unique_keywords = list(set(keywords_list))

SQL练习---619.出现一次的最大数字

题目 分析 首先确定表的来源只有一个表数字表&#xff0c;再者判断他是不是单一数字&#xff0c;&#xff08;想到的是直接按数字分组&#xff0c;通过count函数来判断是否为单一数子&#xff09;&#xff0c;然后求最大值。 题解 select Max(num) as num from MyNumbers wh…

Facebook个人主页和公共主页的区别

Facebook个人主页和公共主页是两种不同类型的页面&#xff0c;它们在功能、用途和管理方面上都是存在着一些明显的区别。本文小编则对他们的区别介绍一下。 首先&#xff0c;个人主页是供普通用户使用的&#xff0c;用于展示个人信息和与朋友、家人保持联系。个人主页通常包括…

Prometheus+Ansible+Consul实现服务发现

一、简介 1、Consul简介 Consul 是基于 GO 语言开发的开源工具&#xff0c;主要面向分布式&#xff0c;服务化的系统提供服务注册、服务发现和配置管理的功能。Consul 提供服务注册/发现、健康检查、Key/Value存储、多数据中心和分布式一致性保证等功能。 在没有使用 consul 服…