React Hooks(常用)笔记

一、useState(保存组件状态

1、基本使用

import { useState } from 'react';function Example() {const [initialState, setInitialState] = useState(default);
}

useState(保存组件状态) :React hooks是function组件(无状态组件) ,所以需要useState保存组件状态(不要直接在函数组件中使用let定义变量。因为function没有状态,当function由useState或者props等引发更新的时候,let定义的变量会被重置成初始状态,也就不会发生改变)。

useState是异步更新的返回一个由两个值组成的数组:

  1. 当前的 state在首次渲染时,它将与你传递的 initialState 相匹配。
  2. set函数,它可以让你将 state 更新为不同的值并触发重新渲染。

注意事项

  • useState 是一个 Hook,因此你只能在组件的顶层或自己的 Hook 中调用它。你不能在循环或条件语句中调用它。如果你需要这样做,请提取一个新组件并将状态移入其中。
  • 在严格模式中,React 将 两次调用初始化函数,以 ​​​​帮你找到意外的不纯性。这只是开发时的行为,不影响生产。如果你的初始化函数是纯函数(本该是这样),就不应影响该行为。其中一个调用的结果将被忽略。

2、解决useState异步更新不及时的问题

  • useEffect(推荐)

通过useEffect监听可以获取到最新的值

  • 传入函数(推荐)(可以让页面上保持最新的值,但是不可以 立马获取到最新的值)

通过传入函数,可以根据先前的 state 更新 state ,但是不能立马获取值。

这是因为直接调用 set 函数 不会更新已经运行代码中的 count1状态变量。因此,即使调用多个 setCount1(count1 + 1) 调用都是拿最初始的值+1 。

通过函数调setCount((count2)=>count2 + 1)是更新函数。它获取 待定状态 ,并从中计算 下一个状态,所以每次拿到的都是最新的值.

但是由于useState是异步的,所以我们在下方打印并不能获取到最新的值,如果想获取到最新的值,可以结合useEffect使用。

​
import React, { useState, useRef } from 'react'; function Example() {const [count1, setCount1] = useState(0); const [count2, setCount2] = useState(0); const handleClick = () => { setCount(count1 + 1); setCount(count1 + 1); console.log('count1:', count1); // 输出旧的count值 0 ,页面上显示 1setCount((count2)=>count2 + 1); setCount((count2)=>count2 + 1); console.log('count2:', count2); // 输出旧的count值 0,页面上显示 2}; return ( <div><p>Count: {count}</p> <button onClick={handleClick}>Increment</button></div> ); 
}​
  • 通过useRef解决(不推荐)(可以获取最新的值,但是写起来比较麻烦)

通过useRef可以解决useState更新不及时的问题。useRef是React提供的一个Hook,它可以用来在函数组件中存储和访问可变的值。

当我们使用useState来更新状态时,由于useState是异步的,所以在更新状态后立即访问状态的值可能会得到旧的值。这时可以使用useRef来保存状态的引用,以便在需要时获取最新的值。

具体的解决方法如下:

  1. 使用useRef创建一个引用变量:const stateRef = useRef(initialState);,其中initialState是状态的初始值。
  2. 在需要获取最新状态值的地方,通过stateRef.current来访问最新的状态值。

下面是一个示例代码:

​
import React, { useState, useRef } from 'react'; function Example() {const [count, setCount] = useState(0); const countRef = useRef(count); const handleClick = () => { setCount(count + 1); countRef.current = count + 1; console.log('count:', count); // 输出旧的count值 0console.log('countRef:', countRef.current); // 输出最新的count值 1}; return ( <div><p>Count: {count}</p> <button onClick={handleClick}>Increment</button></div> ); 
}​

二、useEffect(处理副作用和 useLayoutEffect (同步执行副作用)

1、基本使用

useEffect(() => {//effect在这里执行副作用return () => {//cleanup清理代码在这里};
}, [依赖的状态;空数组,表示不依赖])useLayoutEffect(() => {//effect在这里执行副作用return () => {//cleanup清理代码在这里};
}, [依赖的状态;空数组,表示不依赖])

 useEffectuseLayoutEffect接收两个参数,第一个参数是一个回调函数,用于定义副作用操作逻辑,第二个参数是一个依赖数组,可以指定副作用操作的触发条件。

ps:

  • 依赖数组监听对象和数组是浅比较,只有地址发生变化了,才会进入useEffect,所以每次修改数组和对象,都要返回一个新对象或者新数组。我们也可以使用JSON.stringify()把对象或者数组转换成字符串监听(出问题了再用)。
  • 依赖数组为空数组的时候,只在页面初始化时调用。如果此时回调函数里面有return方法,会在离开页面时触发,可以在return方法里面销毁定时器。

2、区别

useEffect(处理副作用)useLayoutEffect (同步执行副作用)都是在组件渲染完成后执行的副作用函数:

  • useEffect(异步):会在浏览器绘制完成后异步执行,不会阻塞页面渲染。因此,它适用于大多数情况下的副作用操作,比如数据获取、订阅事件、修改DOM等。由于是异步执行,可能会导致页面闪烁或者用户看到不一致的UI。
  • useLayoutEffect(同步):在浏览器绘制之前同步执行,即会阻塞页面渲染。这使得它更适合处理需要立即更新UI的副作用操作,比如修改DOM样式、测量元素尺寸等。由于是同步执行,可以确保在页面渲染前完成副作用操作,避免了页面闪烁或不一致的UI。

总结:虽然useEffect会造成回流和重绘,但由于它的执行时机是在浏览器完成绘制后,所以对页面性能的影响较小。而useLayoutEffect的同步执行可能会导致页面卡顿。所以官方建议优先使用 useEffect

ps:补充浏览器渲染过程如下(详细流程在这)

3、什么时候应该使用 useLayoutEffect(举例)?

  •  添加平滑滚动

可以用于向容器元素添加平滑滚动功能。设置事件侦听器以侦听窗口对象上的滚动事件并调用 handlescroll 函数。该函数将使用带有 { top: 0, behavior: 'smooth' } 作为参数的 scrollTo 方法将容器平滑地滚动到顶部。

import React, { useRef, useLayoutEffect } from 'react';const SmoothScrolling = () => {const containerRef = useRef(null);useLayoutEffect(() => {const container = containerRef.current;const handleScroll = () => {// 平滑滚动到容器顶部container.scrollTo({top: 0,behavior: 'smooth',});};// 当组件被挂载时滚动到顶部handleScroll();// 添加事件侦听器以在后续滚动时滚动到顶部window.addEventListener('scroll', handleScroll);return () => {window.removeEventListener('scroll', handleScroll);};}, []);return (<div ref={containerRef}>{/* 你的内容 */}</div>);
};
  • 动画元素

为元素的不透明度设置动画。元素的初始不透明度设置为 0,然后使用 setTimeout 函数在 1000 毫秒的延迟后将其设置为 1。然后 useLayoutEffect 在组件挂载后应用动画。当组件被卸载时,元素的不透明度重置为 0。

mport React, { useRef, useLayoutEffect } from 'react';const AnimatingElements = () => {const elementRef = useRef(null);useLayoutEffect(() => {const element = elementRef.current;// 在挂载时为元素的不透明度设置动画element.style.opacity = 0;setTimeout(() => {element.style.opacity = 1;}, 1000);return () => {// 组件卸载时清理动画element.style.opacity = 0;};}, []);return <div ref={elementRef}>Animate me!</div>;
};
  • 自动对焦输入框

使用 它在组件挂载时自动聚焦到输入字段。我们继续使用 ref 访问输入元素。在 useLayoutEffect 中,我们调用输入元素上的 focus 方法来赋予它焦点。因为我们希望它只运行一次,所以我们将依赖项数组留空 ([])。

注意:对于此示例,没有清理功能,因为在卸载组件时不需要撤消焦点。

import React, { useRef, useLayoutEffect } from 'react';const AutoFocusInput = () => {const inputRef = useRef(null);useLayoutEffect(() => {inputRef.current.focus();}, []);return <input ref={inputRef} />;
};

三、useCallback(记忆函数) 和 useMemo (记忆组件)

import React, { useState, useCallback, useMemo } from 'react';const ExampleComponent = () => {const [count, setCount] = useState(0);// 使用useCallback来缓存一个回调函数,用于修改useState的值const handleClick = useCallback(() => {setCount(count + 1);}, [count]);// 使用useMemo来缓存一个计算结果(相当于vue的计算属性)const doubledCount = useMemo(() => {return count * 2;}, [count]);return (<div><p>Count: {count}</p><p>Doubled Count: {doubledCount}</p><button onClick={handleClick}>Increase Count</button></div>);
}export default ExampleComponent;

useCallback 和 useMemo 都是用来优化性能的hooks(用于优化性能和避免不必要的重新渲染)。在这个例子中,我们使用了useCallback来缓存handleClick回调函数,以便在count更新时不会重新创建函数。而useMemo则用来缓存doubledCount的计算结果,以便在count更新时不会重新计算。这样可以帮助提高组件的性能。

useCallback用于创建一个记忆化的回调函数。它接收一个回调函数和一个依赖数组作为参数,并返回一个记忆化后的回调函数。当依赖数组中的值发生变化时,才会重新创建回调函数。这样可以避免在每次渲染时都创建新的回调函数,提高性能。

useMemo用于创建一个记忆化的值。它接收一个计算函数和一个依赖数组作为参数,并返回一个记忆化后的值。当依赖数组中的值发生变化时,才会重新计算值。这样可以避免在每次渲染时都重新计算值,提高性能。

四、useRef(保存引用值)

import React, { useRef, useEffect } from 'react';const RefExample = () => {const inputRef = useRef(null);useLayoutEffect(() => {// 在组件加载后自动聚焦到输入框inputRef.current.focus();}, []);return (<div><input type="text" ref={inputRef} /><button onClick={() => inputRef.current.focus()}>Focus Input</button></div>);
}export default RefExample;

useRef的作用是创建一个可变的ref对象,其current属性被初始化为传入的参数(可以是任意值)。useRef返回的ref对象在组件的整个生命周期中保持不变,不会因为组件重新渲染而改变。这使得useRef非常适合用于存储和访问DOM元素或者在组件渲染周期之间存储任意可变值的情况。

在上面这个例子中,我们使用了useRef来创建一个引用inputRef,并将其绑定到一个input元素上。在组件加载后,我们使用useEffect来自动聚焦到输入框,并且通过按钮点击也可以聚焦到输入框。 

useRef 经常被用于管控React hooks中的定时器,我们使用useRef创建了一个intervalRef引用,用来存储定时器的ID。当点击"Start Timer"按钮时,我们使用setInterval启动定时器,并将定时器ID存储在intervalRef.current中。当点击"Stop Timer"按钮时,我们使用clearInterval停止定时器。在组件卸载时,我们通过useEffect的清理函数清除定时器,以避免内存泄漏。如下

import React, { useRef, useEffect } from 'react';const TimerExample = () => {const intervalRef = useRef(null);const startTimer = () => {intervalRef.current = setInterval(() => {console.log('Timer tick');}, 1000);};const stopTimer = () => {clearInterval(intervalRef.current);};useEffect(() => {return () => {clearInterval(intervalRef.current);};}, []);return (<div><button onClick={startTimer}>Start Timer</button><button onClick={stopTimer}>Stop Timer</button></div>);
}export default TimerExample;

 五、useReducer(状态管理)和useContext(全局状态共享)

1、useReducer基本使用

  • 它的作用是根据传入的 reducer 函数和初始状态,返回当前状态和派发更新的函数。
  • 适用于复杂的状态逻辑,可以相关的状态和操作集中在一起,便于维护和扩展。 但是相对于useState,使用useState需要编写更多的代码。
  • 如下:state 是当前状态的值,dispatch 是派发更新的函数,reducer 是一个接受当前状态和操作类型的函数,用于根据操作类型更新状态,{count: 0 } 是初始状态的值。
import React, { useReducer } from 'react';// 定义reducer函数
const reducer = (state, action) => {switch (action.type) {case 'INCREMENT':return { count: state.count + 1 };case 'DECREMENT':return { count: state.count - 1 };default:return state;}
};const Counter = () => {// 使用useReducer定义状态和dispatch函数const [state, dispatch] = useReducer(reducer, { count: 0 });return (<div><p>Count: {state.count}</p><button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button><button={() => dispatch({ type: 'DECREMENT' })}>Decrement</button></div>);
};export default Counter;

2、useContext基本使用

  • 用于在React组件中共享全局状态。通过在组件树中的某个父组件上使用Context.Provider来提供Context的值。子组件可以使用useContext来获取Context的值。
  • 方便实现全局状态共享,避免了props层层传递的麻烦。不适用于所有场景,如果只是简单的状态共享,可以考虑其他方案。
import React, { useContext } from 'react';// 创建一个Context对象
const ThemeContext = React.createContext();const ThemeButton = () => {// 使用useContext获取Context的值const theme = useContext(ThemeContext);return (<button style={{ background: theme.background, color: theme.color }}>Theme Button</button>);
};const App = () => {// 提供Context的值const theme = { background: 'blue', color: 'white' };return (<ThemeContext.Provider value={theme}><ThemeButton /></ThemeContext.Provider>);
};export default App;

3、useReducer和useContext的组合使用(减少层级)

import React from 'react';var GlobalContext = React.createContext();
// 注意此时的reduecer 返回值是一个对象 {isShow:false,list:[]}
function App(props) {let [state, dispatch] = useReducer(reducer, { isShow: true, list: [] });return (<GlobalContext.Providervalue={{dispatch,}}><div>{state.isShow ? <div>我是选项卡</div> : null}{props.children}</div></GlobalContext.Provider>);
}
function Detail() {var { dispatch } = useContext(GlobalContext);useEffect(() => {//隐藏dispatch({type: 'Hide',payload: false,});return () => {//显示dispatch({type: 'Show',payload: true,});};}, []);return <div>detail</div>;
}

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

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

相关文章

IDEA生成测试类

方法一 具体流程: 选中要生成的测试类------------>选择code选项------------>选择Generate选项---------->选择test选项---------->选择要生成的方法 第一步: 光标选中需要生成测试类的类 找到code选项 选中Generate选项 选中test选项 选中你要生成的测试…

简单的jmeter上传文件脚本

1、设置上传接口的headers的值 2、添加post请求

数据结构系列-二叉树之前序遍历

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 这篇文章&#xff0c;我们主要的内容是对二叉树当中的前历的算法进行讲解&#xff0c;二叉树中的算法所要求实现的是 从根到左子树再到右子树的遍历顺序&#xff0c;可能这样不太…

什么是用户体验(UX)文案,为什么它很重要?

网上购物如今比以往任何时候都更加相关。所以我们将以此为例说明什么是用户体验&#xff08;UX&#xff09;文案&#xff0c;以及为什么它很重要。 假设你去了一个在线商店。你需要执行一系列操作&#xff1a; 找到合适的部分选择你感兴趣的产品弄清楚它们是什么&#xff0c;…

2.6设计模式——Flyweight 享元模式(结构型)

意图 运用共享技术有效地支持大量细粒度的对象。 结构 其中 Flyweight描述一个接口&#xff0c;通过这个接口Flyweight可以接受并作用于外部状态。ConcreteFlyweight实现Flyweight接口&#xff0c;并作为内部状态&#xff08;如果有&#xff09;增加存储空间。ConcreteFlywe…

Unity AssetsBundle打包

为什么要使用AssetsBundle包 减少安装包的大小 默认情况下&#xff0c;unity编译打包是对项目下的Assets文件夹全部内容进行压缩打包 那么按照这个原理&#xff0c;你的Assets文件夹的大小将会影响到你最终打包出的安装包的大小&#xff0c;假如你现在正在制作一个游戏项目&…

没有文件服务器,头像存哪里合适

没有文件服务器&#xff0c;头像存哪里合适 视频在bilibili&#xff1a;没有文件服务器&#xff0c;头像存哪里合适 1. 背景 之前有同学私信我说&#xff0c;他的项目只是想存个头像&#xff0c;没有别的文件存储需求&#xff0c;不想去用什么Fastdfs之类的方案搭建文件服务…

【C++杂货铺】多态

目录 &#x1f308;前言&#x1f308; &#x1f4c1;多态的概念 &#x1f4c1; 多态的定义及实现 &#x1f4c2; 多态的构成条件 &#x1f4c2; 虚函数 &#x1f4c2; 虚函数重写 &#x1f4c2; C11 override 和 final &#x1f4c2; 重载&#xff0c;覆盖&#xff08;重写…

ARM学习(26)链接库的依赖查看

笔者今天来聊一下查看链接库的依赖。 通常情况下&#xff0c;运行一个可执行文件的时候&#xff0c;可能会出现找不到依赖库的情况&#xff0c;比如图下这种情况&#xff0c;可以看到是缺少了license.dll或者libtest.so&#xff0c;所以无法运行。怎么知道它到底缺少什么dll呢&…

HarmonyOS-Next开源三方库 MPChart:打造出色的图表体验

点击下载源码https://download.csdn.net/download/liuhaikang/89228765 简介 随着移动应用的不断发展&#xff0c;数据可视化成为提高用户体验和数据交流的重要手段之一。在 OpenAtom OpenHarmony&#xff08;简称“OpenHarmony”&#xff09;应用开发中&#xff0c;一个强大而…

线性代数:抽象向量空间

一、说明 有些函数系列极具线性代数的向量特征。这里谈及多项式构成函数的线性代数意义。问题是这个主题能展开多少内涵&#xff1f;请看本文的论述。 二、线性空间和向量 让我先问你一个简单的问题。什么是向量&#xff1f;为了方便起见&#xff0c;二维箭头从根本上说是平…

OpenHarmony实战开发—进程间通讯

版本&#xff1a;v3.2 Beta5 进程模型 OpenHarmony的进程模型如下图所示&#xff1a; 应用中&#xff08;同一包名&#xff09;的所有UIAbility、ServiceExtensionAbility、DataShareExtensionAbility运行在同一个独立进程中&#xff0c;即图中绿色部分的“Main Process”。…

python自定义交叉熵损失,再和pytorch api对比

背景 我们知道&#xff0c;交叉熵本质上是两个概率分布之间差异的度量&#xff0c;公式如下 其中概率分布P是基准&#xff0c;我们知道H(P,Q)>0&#xff0c;那么H(P,Q)越小&#xff0c;说明Q约接近P。 损失函数本质上也是为了度量模型和完美模型的差异&#xff0c;因此可以…

网御星云防火墙策略配置

网御星云防火墙配置 1. 初始设定2. 网络配置3. 安全规则和策略4. 监控和维护零基础入门学习路线视频配套资料&国内外网安书籍、文档网络安全面试题 1. 初始设定 接入网络&#xff1a; 在开始配置之前&#xff0c;确保你的网御星云防火墙正确连接到网络。这通常涉及将WAN接…

07 流量回放实现自动化回归测试

在本模块的前四讲里&#xff0c;我向你介绍了可以直接落地的、能够支撑百万并发的读服务的系统架构&#xff0c;包含懒加载缓存、全量缓存&#xff0c;以及数据同步等方案的技术细节。 基于上述方案及细节&#xff0c;你可以直接对你所负责的读服务进行架构升级&#xff0c;将…

【Redis 开发】一人一单,超卖问题(悲观锁,乐观锁,分布式锁)

锁 悲观锁乐观锁第一种&#xff1a;版本号法第二种&#xff1a;CAS法实现乐观锁 悲观锁与乐观锁的比较 一人一单分布式锁Redis实现分布式锁 悲观锁 认为线程问题一定会发生&#xff0c;因此在操作数据库之前先获取锁&#xff0c;确保线程串行执行&#xff0c;例如Synchronized…

51单片机使用两个按钮控制LED灯不同频率的闪烁

#include <reg52.h>sbit button1 P1^1; // 间隔2秒的按钮 sbit button2 P1^5; // 间隔0.6秒的按钮sbit led P1^3;unsigned int cnt1 0; // 设置LED1灯的定时器溢出次数 unsigned int cnt2 0; // 设置LED2灯的定时器溢出次数 unsigned int flg1 0; // 模式1的标识值…

x86 64位的ubuntu环境下汇编(无优化)及函数调用栈的详解

1. 引言 为了深入理解c&#xff0c;决定学习一些简单的汇编语言。使用ubuntu系统下g很容易将一个c的文件编译成汇编语言。本文使用此方法&#xff0c;对一个简单的c文件编译成汇编语言进行理解。 2.示例 文件名&#xff1a;reorder_demo.cpp #include<stdio.h>typede…

强固型车载电脑在智能轨道安全解决方案的应用

智能轨道安全解决方案 信迈提供一系列具有传感、诊断、人工智能和无线功能的车载列车解决方案。它们提供全面的可扩展性和面向未来的车辆、路旁、信号、电力、障碍物检测和数据收集功能。 应用程序: 铁路供电监控车载列车安全保护铁路轨道监控驾驶行为分析 智能车载解决方案…

Django连接数据库

数据库登录命令 mysql -u root -p show databases; Django连接数据库 在settings.py文件中进行配置和修改 DATABASES {default: {ENGINE: django.db.backends.mysql,HOST: 127.0.0.1, # 数据库主机PORT: 3306, # 数据库端口USER: root, # 数据库用户名PASSWORD: 12345…