ReactHooks 官网文档翻译

useCallback(fn, dependencies)

useCallback是一个React Hook,它允许您在重新渲染之间缓存函数定义。

const cachedFn = useCallback(fn, dependencies)

1、参数:

fn:要缓存的函数值。它可以接受任何参数并返回任何值。React将在初始渲染期间返回(而不是调用!)您的函数。在下一次渲染中,如果自上次渲染以来依赖项没有更改,React将再次为您提供相同的函数。否则,它将为您提供在当前渲染过程中传递的函数,并将其存储起来,以备以后重用。React不会调用您的函数。函数将返回给您,以便您可以决定何时以及是否调用它。

dependencies:fn代码内部引用的所有反应值的列表。反应值包括props、state以及直接在组件体内声明的所有变量和函数。如果您的linter配置为React,它将验证每个React值是否正确指定为依赖项。依赖项列表必须具有恒定数量的项,并且像[dep1,dep2,dep3]一样以内联方式编写。React将使用Object.is的比较算法将每个依赖项与其以前的值进行比较。

2、返回值:

在初始渲染时,useCallback返回您传递的fn函数。
在随后的渲染过程中,它将从上次渲染中返回一个已经存储的fn函数(如果依赖项没有更改),或者返回您在此渲染过程中传递的fn函数。

3、告诫:

useCallback是一个Hook,所以您只能在组件的顶层或您自己的Hook中调用它。不能在循环或条件内部调用它。如果需要,请提取一个新组件并将状态移动到其中。

4、用法:

在以下渲染中,React将把依赖项与您在上一次渲染中传递的依赖项进行比较。如果任何依赖项都没有更改(与Object.is相比),useCallback将返回与以前相同的函数。否则,useCallback将返回在此渲染中传递的函数。

import { useCallback } from 'react';export default function ProductPage({ productId, referrer, theme }) {const handleSubmit = useCallback((orderDetails) => {post('/product/' + productId + '/buy', {referrer,orderDetails,});}, [productId, referrer]);

默认情况下,当组件重新渲染时,React会递归地重新渲染其所有子级。这就是为什么当ProductPage使用不同的主题重新渲染时,ShippingForm组件也会重新渲染。这对于不需要太多计算即可重新渲染的组件来说很好。但是,如果验证了重新渲染的速度较慢,则可以通过将其包装在备忘录中,告诉ShippingForm在其道具与上次渲染相同时跳过重新渲染

function ProductPage({ productId, referrer, theme }) {// ...return (<div className={theme}><ShippingForm onSubmit={handleSubmit} /></div>);

使用了memo包裹子组件只有prop变化时才会重新渲染,否则就跳过重新渲染

import { memo } from 'react';const ShippingForm = memo(function ShippingForm({ onSubmit }) {// ...
});

在JavaScript中,函数(){}或()=>{}总是创建不同的函数,类似于{}对象文字总是创建新对象的方式。通常情况下,这不会是一个问题,但这意味着ShippingForm道具将永远不会相同,您的备忘录优化也不会起作用。在这个例子中父组件的prop变化时函数会重新创建,即使子组件使用memeo依然不起作用,因为handleSubmit每次都不同

function ProductPage({ productId, referrer, theme }) {// Tell React to cache your function between re-renders...const handleSubmit = useCallback((orderDetails) => {post('/product/' + productId + '/buy', {referrer,orderDetails,});}, [productId, referrer]); // ...so as long as these dependencies don't change...return (<div className={theme}>{/* ...ShippingForm will receive the same props and can skip re-rendering */}<ShippingForm onSubmit={handleSubmit} /></div>);
}

现在我们就可以将他等着在useCallback,只有依赖项变化时才会返回新的函数定义。一般情况下我们不必将函数使放在useCallback中,除非处于某种特定原因

function ProductPage({ productId, referrer, theme }) {// Tell React to cache your function between re-renders...const handleSubmit = useCallback((orderDetails) => {post('/product/' + productId + '/buy', {referrer,orderDetails,});}, [productId, referrer]); // ...so as long as these dependencies don't change...return (<div className={theme}>{/* ...ShippingForm will receive the same props and can skip re-rendering */}<ShippingForm onSubmit={handleSubmit} /></div>);
}

5、useCallack和useMemo 的区别

useMemo缓存调用函数的结果。useCallback缓存函数本身。

 const requirements = useMemo(() => { // Calls your function and caches its resultreturn computeRequirements(product);}, [product]);const handleSubmit = useCallback((orderDetails) => { // Caches your function itselfpost('/product/' + productId + '/buy', {referrer,orderDetails,});}, [productId, referrer]);

可以想象成这样:

// Simplified implementation (inside React)
function useCallback(fn, dependencies) {return useMemo(() => fn, dependencies);
}

6、何时使用useCallack

如果你的应用程序像这个网站,并且大多数交互都很粗糙(比如替换一个页面或整个部分),那么通常不需要记忆。另一方面,如果你的应用程序更像一个绘图编辑器,并且大多数交互都是细粒度的(比如移动的形状),那么你可能会发现记忆非常有用。
使用useCallback缓存函数只有在少数情况下才有价值:
1、您将函数作为餐厨传递给了memo包裹的子组件
2、您传递的函数稍后将用作某个Hook的依赖项。例如,包装在useCallback中的另一个函数依赖于它,或者您依赖于useEffect中的此函数。
在其他情况下,用useCallback包装函数没有任何好处。这样做也没有重大危害,所以一些团队选择不考虑个别案例,并尽可能多地记忆。缺点是代码的可读性变差。此外,并非所有的记忆都是有效的:一个“总是新的”值就足以破坏整个组件的记忆。

useContext(SomeContext)

useContext是一个React Hook,它允许您从组件中读取和订阅上下文。

import { useContext } from 'react';function MyComponent() {const theme = useContext(ThemeContext);// ...

1、参数

SomeContext:您之前使用createContext创建的上下文。

2、返回值

useContext返回调用组件的上下文值,返回的值始终是最新的

3、告诫

相应的<Context.Provider>需要位于执行useContext()调用的组件之上。

4、用法

深层数据传递、通过context传递更新数据
react 会找桑钱上下文最近的provider,不论层级多深都可以使用useContext(ThemeContext),访问到

function MyPage() {return (<ThemeContext.Provider value="dark"><Form /></ThemeContext.Provider>);
}function Form() {// ... renders buttons inside ...
}

useEffect(setup, dependencies?)

useEffect是一个React Hook,用于将组件与外部系统同步。

import { useEffect } from 'react';
import { createConnection } from './chat.js';function ChatRoom({ roomId }) {const [serverUrl, setServerUrl] = useState('https://localhost:1234');useEffect(() => {const connection = createConnection(serverUrl, roomId);connection.connect();return () => {connection.disconnect();};}, [serverUrl, roomId]);// ...
}

1、参数

setup:具有Effect逻辑的函数。您的设置函数也可以选择返回一个清理函数。
可选依赖项:设置代码内部引用的所有反应值的列表。反应值包括props、state以及直接在组件体内声明的所有变量和函数。

2、用法

连接到外部系统:某些组件在页面上显示时,需要保持与网络、某些浏览器API或第三方库的连接。这些系统不受React控制,所以它们被称为外部系统。
例如:
一个由setInterval()和clearInterval.()管理的计时器。
使用window.addEventListener()和window.removeEventLister()的事件订阅。
带有API的第三方动画库,如animation.start()和animation.reset()

3、解释

感觉官网的解释有些晦涩,一般我们是这么理解的
可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
情况一:不传第二个参数(模拟 class 组件的 DidMount 和 DidUpdate )

useEffect(() => {
/** 执行逻辑 */
}) 

情况二:传递一个空数组(模拟 class 组件的 DidMount )

useEffect(() => {
/** 执行逻辑 */
},[]) 

情况三:传递数组有依赖项(模拟 class 组件的 DidUpdate )

useEffect(() => {
/** 执行逻辑 */
},[age,name])  

情况四:第一个参数可以返回一个回调函数(模拟 WillUnMount 组件销毁的时候 停止计时器 )

const [time, setTime] = useState(0)
useEffect(() => {const InterVal = setInterval(() => {setTime(time + 1)},1000)return () => {clearInterval(InterVal )}
},[])

useMemo(calculateValue, dependencies)

useMemo是一个React Hook,可以在重新渲染之间缓存计算结果。

import { useMemo } from 'react';function TodoList({ todos, tab }) {const visibleTodos = useMemo(() => filterTodos(todos, tab),[todos, tab]);// ...
}

1、参数

calculateValue:计算要缓存的值的函数。
dependencies:calculateValue代码内部引用的所有反应值的列表。

2、返回值

在初始呈现时,useMemo返回不带参数的调用calculateValue的结果。
在接下来的渲染过程中,它将返回上次渲染中已经存储的值(如果依赖项没有更改),或者再次调用calculateValue,并返回calculateValue返回的结果。

3、用法

跳过昂贵的计算

4、怎样算昂贵的计算

一般来说,除非您正在创建或循环数千个对象,否则这可能并不昂贵。如果你想获得更多的信心,你可以添加一个控制台日志来测量在一段代码中花费的时间:

console.time('filter array');
const visibleTodos = filterTodos(todos, tab);
console.timeEnd('filter array');

如果记录的总时间加起来相当大(比如1毫秒或更长),那么将计算结果记忆起来可能是有意义的。作为实验,您可以将计算结果封装在useMemo中,以验证该交互的总记录时间是否减少。

5、何时使用useMemo

1、计算较慢,并且依赖值很少变化
2、将该函数结果作为参数传给memo包裹的子组件
3、该结果作为其他hook的依赖项
在其他情况下,将计算包装在useMemo中没有任何好处。这样做也没有重大危害,所以一些团队选择不考虑个别案例,并尽可能多地记忆。这种方法的缺点是代码的可读性变差

useState(initialState)

useState是一个React Hook,它允许您将状态变量添加到组件中。

import { useState } from 'react';function MyComponent() {const [age, setAge] = useState(28);const [name, setName] = useState('Taylor');const [todos, setTodos] = useState(() => createTodos());// ...

1、参数

initialState:您希望状态初始为的值。它可以是任何类型的值,但函数有一种特殊的行为。此参数在初始渲染后将被忽略。
如果将函数作为initialState传递,它将被视为初始值设定项函数。

2、返回值

current state :当前状态,在第一次渲染期间,它将与您通过的initialState相匹配。
set函数:用于将状态更新为不同的值并触发重新渲染。您可以直接传递下一个状态,也可以传递根据上一个状态计算的函数

setName('Taylor');setAge(a => a + 1);

3、用法

向组件添加状态,React将存储下一个状态,使用新值再次渲染组件,并更新UI。

import { useState } from 'react';function MyComponent() {const [age, setAge] = useState(42);const [name, setName] = useState('Taylor');// ...

4、定义对象

您可以将对象和数组置于状态。在React中,状态被认为是只读的,所以您应该替换它,而不是突变现有的对象。

// 🚩 Don't mutate an object in state like this:
form.firstName = 'Taylor';
// ✅ Replace state with a new object
setForm({...form,firstName: 'Taylor'
});

5、避免传入函数调用结果为初始值

 const [todos, setTodos] = useState(createInitialTodos());

尽管createInitialTodos()的结果仅用于初始渲染,但您仍在每次渲染时调用此函数。如果创建大型数组或执行昂贵的计算,这可能是浪费。

  const [todos, setTodos] = useState(createInitialTodos);

要解决此问题,可以将其作为初始值设定项函数传递给useState您传递的是函数本身createInitialTodos,而不是调用它的结果createInitialTodos()。如果您将函数传递给useState,React只会在初始化期间调用它。

useRef(initialValue)

useRef是一个React Hook,它允许您引用渲染不需要的值。

mport { useRef } from 'react';function MyComponent() {const intervalRef = useRef(0);const inputRef = useRef(null);// ...

1、参数

initialValue:您希望ref对象的当前属性初始为的值。它可以是任何类型的值。此参数在初始渲染后将被忽略。

2、返回值

current:最初,它被设置为您传递的initialValue。您可以稍后将其设置为其他内容。

3、用法

①使用ref定义一个无需引起页面重新渲染的状态
改变一个ref的值不会触发重新渲染。这意味着引用非常适合存储不影响组件视觉输出的信息。

function handleStopClick() {const intervalId = intervalRef.current;clearInterval(intervalId);
}

②使用ref操作DOM

使用ref来操作DOM是特别常见的。React对此有内置支持。
首先,声明一个初始值为null的ref对象:

import { useRef } from 'react';function MyComponent() {const inputRef = useRef(null);// ...return <input ref={inputRef} />;

React创建DOM节点并将其放在屏幕上后,React将把ref对象的当前属性设置为该DOM节点。现在,您可以访问<input>的DOM节点,并调用focus()等方法:
③ 避免重新创建引用内容
React将初始ref值保存一次,并在下次渲染时忽略它。

function Video() {const playerRef = useRef(new VideoPlayer());

尽管新VideoPlayer()的结果仅用于初始渲染,但您仍在每次渲染时调用此函数。如果创建昂贵的对象,这可能是浪费。
要解决此问题,您可以按如下方式初始化ref:

function Video() {const playerRef = useRef(null);if (playerRef.current === null) {playerRef.current = new VideoPlayer();}// ...

4、将ref传给自定义组件

默认情况下,组件不会将其DOM节点公开给父组件,这么写会报错

const inputRef = useRef(null);
return <MyInput ref={inputRef} />;

如果您希望MyInput的父组件能够访问<input>DOM节点,则必须选择使用forwardRef:

import { forwardRef } from 'react';const MyInput = forwardRef(({ value, onChange }, ref) => {return (<inputvalue={value}onChange={onChange}ref={ref}/>);
});export default MyInput;

useImperativeHandle(ref, createHandle, dependencies?)

1、解释

React的useImperativeHandle是自定义钩子,可以让父组件获取并执行子组件内某些自定义函数(方法),或者获取子组件的状态。

2、本质

useImperativeHandle本质上其实是子组件将自己内部的函数(方法)通过useImperativeHandle添加到父组件中useRef定义的对象中。如果想使用useImperativeHandle,那么还要结合useRef、React.forwardRef一起使用。

3、示例

结合这个例子:
使用forwardRef后父组件可以访问子组件的Dom

import { forwardRef } from 'react';const MyInput = forwardRef(({ value, onChange }, ref) => {return (<inputvalue={value}onChange={onChange}ref={ref}/>);
});export default MyInput;

假设您不想公开整个<input>DOM节点,但希望公开它的两个方法:focus和scrollIntoView。要做到这一点,请将真实的浏览器DOM保存在一个单独的引用中。然后使用useImperativeHandle只使用您希望父组件调用的方法来公开句柄:

import { forwardRef, useRef, useImperativeHandle } from 'react';const MyInput = forwardRef(function MyInput(props, ref) {const inputRef = useRef(null);useImperativeHandle(ref, () => {return {focus() {inputRef.current.focus();},scrollIntoView() {inputRef.current.scrollIntoView();},};}, []);return <input {...props} ref={inputRef} />;
});

现在,如果父组件获得对MyInput的引用,它将能够调用其上的焦点和scrollIntoView方法。但是,它将无法完全访问底层的<input>DOM节点。

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

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

相关文章

【CSS】实现鼠标悬停图片放大的几种方法

1.背景图片放大 使用css设置背景图片大小100%&#xff0c;同时设置位置和过渡效果&#xff0c;然后使用&#xff1a;hover设置当鼠标悬停时修改图片大小&#xff0c;实现悬停放大效果。 <!DOCTYPE html> <html lang"en"> <head><meta charset…

vue项目使用element-plus

介绍 1.element Plus 是一套基于 Vue.js 的组件库&#xff0c;是对饿了么团队的 Element UI 组件库的升级版本。Element Plus 的目标是提供一套更为现代、更好用的 Vue.js UI 组件。 导入 1.1 执行命令: npm install element-plus --save 1.2 在main.js中做如下配置import E…

###C语言程序设计-----C语言学习(4)#

前言&#xff1a;感谢老铁的浏览&#xff0c;希望老铁可以一键三连加个关注&#xff0c;您的支持和鼓励是我前进的动力&#xff0c;后续会分享更多学习编程的内容。现在开始今天的内容&#xff1a; 一. 主干知识的学习 1.字符型数据 &#xff08;1&#xff09;字符型常量 字…

Leetcode541反转字符串Ⅱ(java实现)

我们今天分享的题目是字符串反转的进阶版反转字符串Ⅱ。 我们首先来看题目描述&#xff1a; 乍一看题目&#xff0c;有种懵逼的感觉&#xff0c;不要慌&#xff0c;博主来带着你分析题目&#xff0c;题目要求&#xff1a; 1. 每隔2k个字符&#xff0c;就对2k字符中的前k个字符…

自监督学习

自监督学习指的是不依赖标注数据&#xff0c;模型直接从无标注的大量数据中进行学习。【属于无监督学习的一部分&#xff0c;它在训练过程中有正负样本&#xff0c;但是正负样本不是人工标号得来的&#xff0c;而是通过自己产生的。】 自监督学习总体分成两类&#xff1a;生成式…

muduo源码阅读笔记(11、TcpClient)

muduo源码阅读笔记&#xff08;11、TcpClient&#xff09; Muduo源码笔记系列&#xff1a; muduo源码阅读笔记&#xff08;0、下载编译muduo&#xff09; muduo源码阅读笔记&#xff08;1、同步日志&#xff09; muduo源码阅读笔记&#xff08;2、对C语言原生的线程安全以及…

C++设计模式介绍:优雅编程的艺术

物以类聚 人以群分 文章目录 简介为什么有设计模式&#xff1f; 设计模式七大原则单一职责原则&#xff08;Single Responsibility Principle - SRP&#xff09;开放封闭原则&#xff08;Open/Closed Principle - OCP&#xff09;里氏替换原则&#xff08;Liskov Substitution …

1.27学习总结

今天做了些队列的题&#xff1a; 1.逛画展&#xff08;单调队列&#xff09; 2.打印队列 Printer Queue&#xff08;优先队列&#xff09; 3.[NOIP2010 提高组] 机器翻译(模拟队列) 4.求m区间内的最小值(单调队列板子题) 5.日志统计(滑动窗口&#xff0c;双指针) 总结一下&…

3分钟 docker搭建 帕鲁服务器

1. 安装docker 1.安装依赖环境 yum -y install yum-utils device-mapper-persistent-data lvm22.设置镜像源 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo3.安装docker 3.1 yum makecache fast yum install docker-ce …

MongoDB:从容器使用到 Mongosh、Python/Node.js 数据操作

文章目录 1. 容器与应用之间的关系介绍2. 使用 Docker 容器安装 MongoDB3. Mongosh 操作3.1 Mongosh 连接到 MongoDB3.2 基础操作与 CRUD 4. Python 操作 MongoDB5. Nodejs 操作 MongoDB参考文献 1. 容器与应用之间的关系介绍 MongoDB 的安装有时候并不是那么容易的&#xff0…

消息中间件及java线程池

1. ActiveMQ是什么&#xff1f; Apache ActiveMQ是一个开源的消息中间件&#xff08;Message Oriented Middleware, MOM&#xff09;&#xff0c;它遵循Java消息服务&#xff08;Java Message Service, JMS&#xff09;规范&#xff0c;提供高效、可靠和异步的消息传递功能。Ac…

【从浅到深的算法技巧】初级排序算法 上

5.排序 5.1 初级排序算法 作为对排序算法领域的第一次探索&#xff0c; 我们将学习两种初级的排序算法以及其中种的一个变体。深入学习这些相对简单的算法的原因在于:第一,我们将通过它们熟悉些术语和简单的技巧 第二&#xff0c;这些简单的算法在某些情况下比我们之后将会讨论…

《HelloGitHub》第 94 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 https://github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 …

Redis6基础知识梳理~

初识NOSQL&#xff1a; NOSQL是为了解决性能问题而产生的技术&#xff0c;在最初&#xff0c;我们都是使用单体服务器架构&#xff0c;如下所示&#xff1a; 随着用户访问量大幅度提升&#xff0c;同时产生了大量的用户数据&#xff0c;单体服务器架构面对着巨大的压力 NOSQL解…

openssl3.2 - 测试程序的学习 - test\acvp_test.c

文章目录 openssl3.2 - 测试程序的学习 - test\acvp_test.c概述笔记要单步学习的测试函数备注END openssl3.2 - 测试程序的学习 - test\acvp_test.c 概述 openssl3.2 - 测试程序的学习 将test*.c 收集起来后, 就不准备看makefile和make test的日志参考了. 按照收集的.c, 按照…

换个思维方式快速上手UML和 plantUML——类图

和大多数朋友一样&#xff0c;Jeffrey 在一开始的时候也十分的厌烦软件工程的一系列东西&#xff0c;对工程化工具十分厌恶&#xff0c;觉得它繁琐&#xff0c;需要记忆很多没有意思的东西。 但是之所以&#xff0c;肯定有是因为。对工程化工具的不理解和不认可主要是基于两个逻…

【c++】类对象模型

1.如何计算类对象的大小 class A { public:void PrintA(){cout<<_a<<endl;} private:char _a; }; 问题&#xff1a;类中既可以有成员变量&#xff0c;又可以有成员函数&#xff0c;那么一个类的对象中包含了什么&#xff1f;如何计算一个类的大小&#xff1f; 2…

C++算法之枚举、模拟与排序

1.AcWing 1210.连号区间数 分析思路 由题意是在 1∼N 的某个排列中有多少个连号区间&#xff0c;所以每个数出现并且不重复&#xff01; 如果是连续的&#xff0c;那么Max-Minj-i&#xff08;[i,j]&#xff09; 代码实现 #include<iostream> #include<algorithm>…

关于AOP的@Around特殊处理RequestBody的使用小结

目录 1. 概述 1.1 背景 1.2 源码 2. 测试 2.1 Controller 2.2 SpecialName配置 2.3 RequestConverter 2.4 测试 最近项目上遇到一个这样的需求&#xff1a;用户请求的时候传过来A&#xff0c;在api处理过程中要把A当成B去处理&#xff0c;但是返回的标识中又必须是A作为…

freeswitch智能外呼系统搭建流程

1.获取实时音频数据 media_bug &#xff08;好多mrcp方式也崩溃所以用以下方式&#xff09; 可以参考 方式可以通过socket或者webscoket freeswitch[1.05]用websocket发送mediabug语音流到ASRProxy实现实时质检和坐席辅助 - 知乎 2.webscoket 好多c的库放模块容易崩溃 可以…