(React Hooks)前端八股文修炼Day9

在这里插入图片描述

一 对 React Hook 的理解,它的实现原理是什么

React Hooks是React 16.8版本中引入的一个特性,它允许你在不编写类组件的情况下,使用state以及其他的React特性。Hooks的出现主要是为了解决类组件的一些问题,如复杂组件难以理解、难以重用状态逻辑等,并且还能够捕获组件中的副作用。

常见的React Hooks:

  • useState: 允许你在函数组件中添加state。
  • useEffect: 用来处理副作用,类似于类组件的componentDidMountcomponentDidUpdatecomponentWillUnmount生命周期方法的组合。
  • useContext: 允许你访问Context对象,并订阅其变化。
  • useReducer: 为状态更新提供更复杂的逻辑,类似于Redux中的reducer。
  • useCallback: 返回一个记忆化的回调函数。
  • useMemo: 返回一个记忆化的值。
  • useRef: 返回一个可变的ref对象。
  • useLayoutEffect: 其作用与useEffect相似,但它会在所有的DOM更改之后同步触发重渲染。
  • useImperativeHandle: 自定义使用ref时公开给父组件的实例值。
  • useDebugValue: 在React开发者工具中显示自定义的hook标签。

实现原理:

Hooks的工作原理基于JavaScript的闭包机制。当你在函数组件中调用Hooks时,React内部会维护一个状态数组,每次渲染时,Hooks都会按顺序读取和更新这个数组中的状态。因此,每个Hook都必须在组件的顶层调用,这样React才能够正确地关联Hook和对应的状态。

以下是Hooks的一些关键实现原理:
  1. 状态存储: React为每个组件实例维护一个状态数组。当你使用useStateuseReducer时,它会在此数组中为每个state分配一个位置。

  2. 更新调度: 当你更新一个state,React会标记组件为dirty并安排一次重新渲染。在下一次组件渲染时,useStateuseEffect等Hooks将会使用最新的state和props。

  3. 闭包: Hooks依赖闭包来捕获每一次渲染时的props和state,这也是每次更新可以获取到正确state的原因。

  4. Hook的规则: React要求Hooks必须在函数的最顶层调用,不能在循环、条件或嵌套函数中调用。这是因为React根据Hooks的调用顺序来存储和检索状态。

  5. 调试: React提供了useDebugValue来在React开发者工具中显示自定义Hook的内部状态,使得调试更加方便。

  6. 组件生命周期: useEffectuseLayoutEffect Hooks使得你能够在函数组件中执行副作用,并且可以通过返回一个清理函数来执行清理操作,类似于类组件中的componentWillUnmount

Hooks的这种设计允许你以一种更函数式的方式来编写组件,同时使得状态逻辑更容易被分割和重用。Hooks的实现是React团队在框架内部进行了大量的工作,但开发者可以通过上述Hooks以一种简单直观的方式来利用它们的能力。

二 为什么 useState 要使用数组而不是对象

useState 是 React 提供的一个 Hook,使得开发者可以在函数组件中存储和管理状态。使用 useState,你会得到一对值:当前状态和一个更新它的函数。这个 Hook 使用数组结构的主要原因包括:

1. 返回值命名自由

当你使用数组结构时,你可以自由地给状态和更新函数命名,而不是被迫使用对象的键。这提供了更大的灵活性和简洁性。

const [value, setValue] = useState(initialValue);

在这个例子中,valuesetValue 可以根据你的选择自由命名,例如:

const [count, setCount] = useState(0);

2. 减少嵌套和避免合并状态

如果 useState 返回的是一个对象,你可能需要合并现有状态和新状态,这样更新状态时就更容易出错。数组结构的 useState 鼓励你将状态分割成尽可能多的独立的状态变量,减少了状态更新时的复杂性。

如果是对象,更新状态可能需要这样:

this.setState(prevState => {return { ...prevState, key: newValue };
});

而用 useState,更新状态只需这样:

setValue(newValue);

3. 保持API的简洁和一致性

返回数组意味着 useState 总是返回两个值:当前的状态值和一个函数,用于更新状态。这种一致性无论何时使用 useState 都是不变的,因此易于理解和预测。

4. 保持与React Class组件的setState的行为不同

setState 在类组件中通常是合并状态,而 useState 鼓励你使用多个状态钩子来独立地管理不同的状态变量,这使得状态逻辑更清晰。

5. Hook的设计灵感源自函数式编程

函数式编程中经常会用到元组(Tuple),它是编程中一种将多个值组合成一个紧凑形式的方式。React的Hooks API设计者显然受到了函数式编程中使用元组的启发。

总结

使用数组而不是对象返回 useState 的值,使得状态钩子的使用更加灵活、简单和直观。它鼓励将状态分解为较小的、独立的片段,这有助于组件的维护和避免不必要的复杂性。同时,它也与React的函数式编程哲学保持一致。

三 React Hooks解决了哪些问题

React Hooks 的引入是为了解决 React 开发中的一系列问题和挑战,这些问题主要集中在类组件的使用和函数组件的限制方面。下面是 React Hooks 解决的一些主要问题:

1. 复用状态逻辑的难题

在 Hooks 出现之前,复用组件之间的状态逻辑通常需要依靠高阶组件(HOCs)或渲染道具(Render Props)模式。这些模式虽然功能强大,但容易使组件树变得复杂和深层,难以理解和维护。通过自定义 Hooks,开发者可以更容易地在组件之间共享状态逻辑,而不需要修改组件结构。

2. 复杂组件变得难以理解

类组件中,相关逻辑往往分散在不同的生命周期方法中,这使得跟踪组件的行为变得困难。Hooks 允许将相关代码组织在一起,无论它们是用于数据获取、订阅、还是其他副作用,都可以在一个 useEffect 内部管理,这样使得逻辑更加集中和清晰。

3. 难以理解的 this 关键字

在类组件中,this 关键字的行为经常让人困惑,尤其是在事件处理器和回调函数中。函数组件加上 Hooks 使得你可以避免使用 this,从而让代码更容易编写和理解。

4. 逐渐消失的组件生命周期

随着 React 的发展,一些生命周期方法已经被弃用,并且新的异步渲染模式使得一些生命周期方法的行为变得不可预测。Hooks 提供了一种更加直接和清晰的方式来处理副作用(例如,useEffect),不再依赖于生命周期方法。

5. 函数组件的局限性

在 Hooks 出现之前,函数组件被认为是无状态组件,仅适用于简单的展示逻辑。对于需要状态管理、生命周期方法或性能优化的场合,开发者不得不使用类组件。Hooks 的引入使得函数组件拥有了类组件的几乎所有能力,同时保持了更简洁的语法和更好的可读性。

6. 大型组件重构难题

在使用类组件开发大型应用时,重构或拆分复杂组件往往非常困难。Hooks 允许开发者以更小、更可管理的单元组织代码,使得重构和测试变得更加容易。

通过解决这些问题,React Hooks 提升了 React 开发的体验,使代码更加清晰简洁,提高了开发效率和应用性能。

四 React Hook 的使用限制有哪些

React Hooks 是强大的,但使用它们时需要遵守一些重要的规则和限制。这些规则确保了 Hooks 的正确使用和组件的正确行为。以下是使用 React Hooks 时的主要限制和规则:

只能在函数组件的顶层调用 Hooks

Hooks 必须在函数组件的最顶层调用,不能在循环、条件语句或嵌套函数中调用。这是因为 React 依赖于 Hooks 调用的顺序,如果在这些JavaScript结构中使用Hooks,那么Hooks的调用顺序就会变得不确定。

只能在 React 函数组件或自定义 Hooks 中调用 Hooks

不能在普通的 JavaScript 函数中调用 Hooks。Hooks 是特定于 React 的,它们依靠 React 的上下文来正确工作。如果你想在多个组件之间重用有状态逻辑,可以把它放到自定义 Hook 中。

不要在循环、条件或嵌套函数中调用 Hooks

如前所述,Hooks 应该总是在组件的最顶层调用,以确保每次组件渲染时 Hooks 的调用顺序保持一致。条件语句、循环或嵌套函数可能会使得Hooks的调用次序发生变化,从而破坏其内部状态的管理。

为 Hooks 提供正确的依赖项

对于 useEffectuseMemouseCallback 这类需要依赖数组的 Hooks,确保你已经正确地指定了依赖项。遗漏依赖项或者提供错误的依赖项都可能导致不可预测的行为。

避免在常规函数中调用 Hooks

如果你在常规的 JavaScript 函数中调用 Hooks(这里指的不是函数组件或自定义 Hooks),就会打破规则。Hooks 应该只在函数组件或者自定义 Hooks 中使用。

使用 ESLint 插件来强制执行这些规则

React 团队提供了一个 ESLint 插件 (eslint-plugin-react-hooks),它能帮助开发人员识别违反上述规则的代码。这个插件能够在开发过程中检测违反 Hooks 规则的情况,以减少错误。

理解 Hooks 的闭包行为

Hooks 如 useEffect 会捕获定义时的状态和道具。如果你不小心,可能会在异步操作中引用过时的状态或道具,导致难以发现的错误。因此,使用更新函数形式的 useState 和正确的依赖项列表十分重要。

遵守以上规则,可以保证你的 Hooks 正确地工作,并且你编写的函数组件行为符合预期。

五 useEffect 与 useLayoutEffect 的区别

useEffectuseLayoutEffect 都是 React 的内置 Hooks,它们的作用是让你在函数组件中执行副作用操作。尽管它们的用途相似,但是它们在何时执行副作用方面存在一些关键的区别:

useEffect

  • useEffect 在组件渲染到屏幕之后异步执行副作用。
  • 通常情况下,推荐使用 useEffect 来执行副作用,因为它不会阻塞浏览器更新屏幕,这可以让用户感觉到响应更快。
  • 常用于数据获取、订阅、或者直接操作 DOM 等场景。

useLayoutEffect

  • useLayoutEffect 的调用时机与 componentDidMountcomponentDidUpdate 生命周期方法更为一致,它在 DOM 更新完毕后立即同步执行副作用,但在浏览器进行任何绘制之前。
  • useLayoutEffect 通常用于需要同步更新 DOM 或者需要在浏览器绘制之前进行 DOM 操作来避免闪烁的情况。
  • 因为 useLayoutEffect 会在所有的 DOM 变更之后同步执行,如果你的副作用函数执行较慢,它可能会导致帧率下降。

总结来说,如果你的副作用是跟 DOM 操作或者布局计算有关,且需要同步执行的(比如阅读布局并同步重新渲染的情况),那么使用 useLayoutEffect。否则,推荐使用 useEffect

六 React Hooks在平时开发中需要注意的问题和原因

在使用 React Hooks 进行开发时,需要注意一系列问题,以确保代码的健壯性、性能和可维护性。以下是一些在日常开发中应该注意的关键点及其原因:

1. 遵守规则

  • 不要在循环、条件语句或嵌套函数中调用 Hooks:这可能会导致 Hooks 的调用顺序发生变化,从而破坏 React 内部的状态管理。
  • 只在函数组件或自定义 Hooks 中使用 Hooks:保持 Hooks 的使用环境一致性,避免在非 React 函数中产生不可预期的行为。

2. 依赖列表的正确使用

  • useEffectuseMemouseCallback中正确管理依赖列表:省略依赖或错误地添加依赖可能会导致无限循环、过度渲染或陈旧闭包问题。
  • 避免频繁变化的对象或函数作为依赖:这可能会导致不必要的副作用或计算被频繁触发。使用useMemouseCallback来优化这些依赖。

3. 性能优化

  • 使用React.memouseMemouseCallback来避免不必要的渲染:但要注意过度优化。合理使用这些工具来优化真正需要优化的场景。
  • 谨慎使用大型对象或复杂计算作为依赖:考虑将状态拆分或使用useReducer来管理复杂的组件状态。

4. 清理副作用

  • useEffect中返回清理函数:这对于取消订阅、清除定时器等是必要的,以避免内存泄漏和其他副作用。

5. 自定义 Hooks 的正确使用

  • 合理封装和复用逻辑:通过自定义 Hooks 封装共享逻辑,但要保持其独立性和复用性,避免创建过于具体或耦合的自定义 Hooks。

6. 理解闭包陷阱

  • 在使用函数式更新和延迟执行逻辑时注意闭包陷阱:特别是在useEffect中访问的状态和属性,可能会捕获到旧的闭包值。使用函数式更新或者将依赖列入依赖列表来解决。

7. 状态逻辑的分割

  • 避免在一个组件中使用过多的状态和副作用:考虑将逻辑分割到不同的组件或自定义 Hooks 中,以保持组件的清晰和可管理性。

遵循以上准则,可以帮助你更高效和安全地利用 React Hooks 构建应用,避免常见的陷阱和性能问题。

七 React Hooks 和生命周期的关系

React Hooks 的引入在 React 开发中标志着一个重要的转折点。在 Hooks 出现之前,React 组件的状态管理和副作用处理主要依赖于类组件和其生命周期方法。Hooks 的出现使得在无需编写类组件的情况下,也能使用状态管理和副作用等特性,极大地增强了函数组件的能力。这里,我们将探讨 React Hooks 和生命周期方法之间的关系:

生命周期方法

在类组件中,生命周期方法用于在组件不同阶段执行代码。常用的生命周期方法包括:

  • componentDidMount:组件挂载(插入 DOM 树)后执行
  • componentDidUpdate:组件更新后执行
  • componentWillUnmount:组件卸载(从 DOM 树移除)前执行
  • shouldComponentUpdategetDerivedStateFromPropsgetSnapshotBeforeUpdate 等用于特定的优化和操作

React Hooks 与生命周期的对应

React Hooks 使函数组件能够使用某些与类组件生命周期方法相对应的功能:

  • useState:提供状态管理,相当于类组件的 this.statethis.setState
  • useEffect
    • 可以看作是 componentDidMountcomponentDidUpdatecomponentWillUnmount 的结合。通过在函数组件中调用 useEffect,可以在组件渲染到屏幕后执行副作用操作,也可以通过返回一个清理函数来执行类似 componentWillUnmount 的逻辑。
    • 对于需要精确控制副作用执行时机的场景,useEffect 的第二个参数(依赖数组)提供了这种灵活性,允许组件仅对特定状态的改变作出响应。
  • useLayoutEffect
    • useEffect 类似,但它在 DOM 更新完成后同步执行副作用,这在处理 DOM 布局和样式时特别有用,因为它避免了可能的闪烁问题,相当于 componentDidMountcomponentDidUpdate 的同步版。
  • useMemouseCallback
    • 这两个 Hook 能够帮助你在组件重新渲染时优化性能,它们通过记住计算结果或函数,避免不必要的重新计算或创建,可以在某种程度上与 shouldComponentUpdateReact.memo 进行对比。

通过这些 Hooks,React 不仅简化了状态管理和副作用的处理,也使得在不编写类组件的情况下实现复杂组件成为可能。这种转变促进了函数式编程在 React 开发中的应用,提高了代码的模块化和重用性。

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

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

相关文章

qt-C++笔记之QLabel加载图片

qt-C笔记之QLabel加载图片 —— 2024-04-06 夜 code review! 文章目录 qt-C笔记之QLabel加载图片0.文件结构1.方法一:把图片放在项目路径下,在 .pro 文件中使用 DISTFILES添加图片文件1.1.运行1.2.qt_test.pro1.3.main.cpp 2.方法二:不在 .pr…

《深入Linux内核架构》第2章 进程管理和调度 (2)

目录 2.4 进程管理相关的系统调用 2.4.1 进程复制 2.4.2 内核线程 2.4.3 启动新程序 2.4.4 退出进程 本专栏文章将有70篇左右,欢迎关注,订阅后续文章。 2.4 进程管理相关的系统调用 2.4.1 进程复制 1. _do_fork函数 fork vfork clone都最终调用_…

计算机网络 Telnet远程访问交换机和Console终端连接交换机

一、实验要求和内容 1、配置交换机进入特权模式密文密码为“abcd两位班内学号”,远程登陆密码为“123456” 2、验证PC0通过远程登陆到交换机上,看是否可以进去特权模式 二、实验步骤 1、将一台还没配置的新交换机,利用console线连接设备的…

数学建模-最优包衣厚度终点判别法-二(K-Means聚类)

💞💞 前言 hello hello~ ,这里是viperrrrrrr~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 💥个人主页&#xff…

OpenAI曾转录100万小时视频数据,训练GPT-4

4月7日,纽约时报在官网发布了一篇名为《科技巨头如何挖空心思,为AI收集数据》的技术文章。 纽约时报表示,OpenAI曾在2021年几乎消耗尽了互联网有用的文本数据源。为了缓解训练数据短缺的难题,便开发了知名开源语音识别模型Whispe…

Leetcode 394. 字符串解码

心路历程: 这道题看到括号直接想到栈,五分钟新题直接秒了,一开始以为需要两个栈分别存储数字和非数字,后来发现一个栈就够了,思路如图: 这道题考察的应该是队栈这两种数据结构的转换,因为每次…

C语言比较两个字符串是否相等是很容易的

一、概要 两个字符串char str1[n]和char str2[n] while循环,开始前i置为0,如果两个字符串都没有到末尾,且str1[i]str2[i],则i,循环继续 循环结束之后,如果两个字符串都到了末尾(str1[i]\0 &&…

Java零基础入门-Java反射机制

一、概述 我们都听说过java有个反射机制,通过反射机制我们可以更深入的控制程序的运行过程。例如,在程序进入到运行期间,由用户输入一个类名,然后我们可以动态获取到该类拥有的所有类结构、属性名和方法,甚至还可以任意…

Vue3---基础1(认识,创建)

变化 相对于Vue2,Vue3的变化: 性能的提升 打包大小减少 41% 初次渲染快 55%,更新渲染快133% 内存减少54% 源码的升级 使用 proxy 代替 defineProperty 实现响应式 重写虚拟 DOM 的实现和 Tree-shaking TypeScript Vue3就可以更好的支持TypeSc…

PHP 伪协议:使用 php://input 访问原始 POST 数据

文章目录 参考环境PHP 伪协议概念为什么需要 PHP 伪协议? php://input为什么需要 php://input?更灵活的数据处理减小性能压力 发送 POST 数据HackBarHackBar 插件的获取 $_POST打开 HackBar 插件通过 HackBar 插件发起 POST 请求 基操 enable_post_data_…

Linux——fork复制进程

1)shell: 在计算机科学中,Shell俗称壳(用来区别于核),是指“为使用者提供操作界面”的软件(command interpreter,命令解析器)。它类似于DOS下的COMMAND.COM和后来的cmd.exe。它接收用户命令&…

SpringBoot中的Redis的简单使用

在Spring Boot项目中使用Redis作为缓存、会话存储或分布式锁等组件,可以简化开发流程并充分利用Redis的高性能特性。以下是使用Spring Boot整合Redis的详细步骤: 1. 环境准备 确保开发环境中已安装: Java:用于编写和运行Spring…

微服务-6 Gateway网关

一、网关搭建 此时浏览器访问 localhost:10010/user/list 后正常返回数据,说明网关已生效,其原理流程图如下: 二、网关过滤器 作用:处理一切进入网关的请求和微服务响应。 1. 网关过滤器的分类: a. 某个路由的过滤器 …

LeetCode Meditations:合并 K 排序列表

描述 合并K分类列表 状态: 您有一系列 k 链接-列表 lists ,每个链接-列表按升序排序。 合并所有链接-列表为一个排序的链接-列出并返回。 例如: Input: lists [[1, 4, 5], [1, 3, 4], [2, 6]] Output: [1, 1, 2, 3, 4, 4, 5, 6] Explanatio…

地理信息系统(ArcGIS)在水文水资源、水环境中的应用

刘老师(副教授):来自北京重点高校资深专家,长期从事水资源与水环境、流域污染控制与管理、非点源模拟与控制、环境信息系统开发、环境遥感与GIS应用等领域的研究,发表多篇Sci论文、具有资深的技术底蕴和专业背景。 1、…

MapTracker:Tracking with Strided Memory Fusion for Consistent Vector HD Mapping

参考代码:MapTracker 动机与出发点 为了提升帧间检测的稳定性通常会添加时许信息,这个可以BEV特征处做时序融合,也可以是用当前帧query去cross-attn历史帧信息,则更多的时候是将之前帧信息与当前做融合或者cross-attn实现信息传…

SQL注入sqli_labs靶场第三题

?id1and 11 and 11和?id1and 11 and 11进行测试如果11页面显示正常和原页面一样,并且12页面报错或者页面部分数据显示不正常,那么可以确定此处为字符型注入。 根据报错信息判断为单引号带括号注入 联合查询: 猜解列名 ?id1) order by 3-…

SIC知识--(1):来龙去脉

一、碳化硅的起源 1891年,当时爱德华古德里奇艾奇逊在尝试制造人造金刚石的过程中意外发现了这一材料。艾奇逊将黏土(铝硅酸盐)与粉状焦炭(碳)混合后在电炉中加热,预期得到金刚石,却意外获得了一…

代码随想录35期Day08-字符串

344.反转字符串 位运算 func reverseString(s []byte) {l : 0r : len(s) - 1for l < r {s[l] ^ s[r]s[r] ^ s[l]s[l] ^ s[r]lr--} }541. 反转字符串II 没技巧 func reverseStringRange(s []byte, l int, r int) {if r > len(s) {r len(s) - 1}for l < r {s[l] ^…

Mac安装配置ElasticSearch和Kibana 8.13.2

系统环境&#xff1a;Mac M1 (MacOS Sonoma 14.3.1) 一、准备 从Elasticsearch&#xff1a;官方分布式搜索和分析引擎 | Elastic上下载ElasticSearch和Kibana 笔者下载的是 elasticsearch-8.13.2-darwin-aarch64.tar.gz kibana-8.13.2-darwin-aarch64.tar.gz 并放置到个人…