React中Hooks--useEffect | useState | useCallback | useMemo

一、useEffect

useEffect 是 React 提供的一个 Hook,用于在函数组件中执行副作用操作(side effects),例如数据获取、订阅、或手动更改 DOM 等。useEffect 相当于类组件中的生命周期方法,但是它提供了更多的灵活性。

基本用法

useEffect 接受两个参数:

  1. Effect 函数:这是一个包含副作用操作的函数,它将在组件渲染到屏幕后执行。
  2. 依赖项数组:这个数组定义了 effect 函数依赖的组件状态或属性。如果数组中的值发生变化,effect 函数将重新执行。
示例:
import React, { useState, useEffect } from 'react';

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

  // 基本的 useEffect:类似于 componentDidMount 和 componentDidUpdate
  useEffect(() => {
    console.log('count is updated:', count);
    // 执行副作用操作...
  }, [count]); // 依赖项数组包含 count,当 count 变化时 effect 重新执行

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

清理副作用

useEffect 可以返回一个函数,这个函数在组件卸载或重新渲染前执行,用于清理副作用。

示例:
import React, { useState, useEffect } from 'react';

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

  // 基本的 useEffect:类似于 componentDidMount 和 componentDidUpdate
  useEffect(() => {
    console.log('count is updated:', count);
    // 执行副作用操作...
  }, [count]); // 依赖项数组包含 count,当 count 变化时 effect 重新执行

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

仅在组件挂载时执行

如果你希望副作用仅在组件挂载时执行一次,你可以传递一个空数组 [] 作为 useEffect 的第二个参数。

示例:
import React, { useState, useEffect } from 'react';

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

  // 基本的 useEffect:类似于 componentDidMount 和 componentDidUpdate
  useEffect(() => {
    console.log('count is updated:', count);
    // 执行副作用操作...
  }, [count]); // 依赖项数组包含 count,当 count 变化时 effect 重新执行

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

模拟 componentDidUpdate

如果你需要在组件更新时执行副作用,但不在挂载时执行,你可以使用非空的依赖项数组。

示例:
useEffect(() => {
  // 仅在特定 props 更新时执行
  console.log('特定 props 更新了');
}, [specificProp]); // 依赖项数组包含 specificProp

模拟 componentWillUnmount

如果你需要在组件卸载时执行清理操作,可以返回一个函数。

示例:
useEffect(() => {
  function handleStorageChange() {
    // 处理存储变化
  }
  window.addEventListener('storage', handleStorageChange);

  // 组件卸载时的清理操作
  return () => {
    window.removeEventListener('storage', handleStorageChange);
  };
}, []); // 空依赖项数组,仅在组件挂载时执行一次

总结

useEffect 提供了一种灵活的方式来处理组件的副作用操作,它使得函数组件能够执行原本需要在类组件的生命周期方法中执行的操作。通过依赖项数组,useEffect 能够智能地决定何时执行副作用函数,从而避免不必要的副作用执行和潜在的性能问题。

二、useState

useState 是 React 的一个 Hook,它允许你在函数组件中添加 React 状态。这个 Hook 是 React 16.8+ 版本引入的,并且成为了在函数组件中处理状态的首选方式。

基本用法

useState 接受一个参数:初始状态(可以是任何类型,包括对象、数组、基本类型等)。它返回一个数组,包含两个元素:

  1. 当前状态:组件的状态值。
  2. 更新状态的函数:允许你更新状态,这个函数调用时可以传入一个新的状态值,React 将负责重新渲染组件。
示例:
import React, { useState } from 'react';

function Counter() {
  // 初始化状态为 0
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <button onClick={() => setCount(count - 1)}>Decrement</button>
    </div>
  );
}

在这个例子中,count 是当前的状态值,setCount 是更新这个状态的函数。

使用函数更新状态

你可以在调用更新函数时传递一个函数,这个函数接收上一个状态作为参数,并返回新的状态。这在你需要基于前一个状态来计算新状态时非常有用。

示例:
function Counter() {
  const [count, setCount] = useState(0);

  const incrementCount = () => {
    setCount((prevCount) => prevCount + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={incrementCount}>Increment</button>
    </div>
  );
}

多个状态变量

如果你需要在组件中使用多个状态变量,你可以调用 useState 多次来分别创建它们。

示例:
function Form() {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  // 其他逻辑...

  return (
    <form>
      <input
        type="text"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      {/* 其他表单元素 */}
    </form>
  );
}

总结

useState 是函数组件中处理状态的核心 Hook,它使得在函数组件中使用状态变得简单直接。通过 useState,你可以轻松地添加、更新和维护组件的状态,同时享受 React 的响应式更新和性能优化。

三、useCallback

useCallback 是 React 提供的一个 Hook,它用于记忆化(memoization)函数。这意味着 React 会返回同一个函数引用,只要依赖项数组中的值没有变化。这在性能优化中非常有用,特别是当你希望避免在每次渲染时创建新的函数实例,或者在子组件中使用这些函数时。

基本用法

import React, { useCallback } from 'react';

function MyComponent() {
  // 定义一个函数
  const myFunction = (arg) => {
    console.log(arg);
  };

  // 使用 useCallback 记忆化该函数
  const memoizedFunction = useCallback(myFunction, []); // 空依赖数组

  // memoizedFunction 现在是一个记忆化的函数
  // 只要组件没有重新渲染,它就会保持相同的引用
  return <div onClick={() => memoizedFunction('Hello!')}>Click me!</div>;
}

useCallback 是 React 提供的一个 Hook,它用于记忆化(memoization)函数。这意味着 React 会返回同一个函数引用,只要依赖项数组中的值没有变化。这在性能优化中非常有用,特别是当你希望避免在每次渲染时创建新的函数实例,或者在子组件中使用这些函数时。

基本用法

 

import React, { useCallback } from 'react'; function MyComponent() { // 定义一个函数 const myFunction = (arg) => { console.log(arg); }; // 使用 useCallback 记忆化该函数 const memoizedFunction = useCallback(myFunction, []); // 空依赖数组 // memoizedFunction 现在是一个记忆化的函数 // 只要组件没有重新渲染,它就会保持相同的引用 return <div onClick={() => memoizedFunction('Hello!')}>Click me!</div>; }

参数说明

  • 第一个参数:要记忆化的函数。
  • 第二个参数:依赖项数组。只有当这个数组中的值发生变化时,React 才会重新创建函数。

使用场景

  1. 避免子组件的不必要渲染: 当你将回调函数传递给子组件,并且子组件在渲染时使用了这个函数,如果父组件每次渲染都创建一个新的函数实例,子组件可能会因为引用变化而重新渲染。

  2. 优化性能: 通过记忆化,可以减少不必要的计算和 DOM 操作,提高应用性能。

  3. useMemo 结合使用: 有时候,你不仅需要记忆化函数,还需要记忆化计算结果。useCallback 可以与 useMemo 一起使用来优化性能。

  4. 在事件处理器中使用: 事件处理器函数经常作为属性传递给 DOM 元素,使用 useCallback 可以避免因函数引用变化导致的重复渲染。

  5. useEffect 或其他 Hook 中使用: 当回调函数用于 useEffect 或其他 Hook 时,使用 useCallback 可以确保这些 Hook 在不必要的情况下不会运行。

注意事项

  • 当使用 useCallback 时,确保依赖项数组包含了所有外部依赖,以避免记忆化失败。
  • 如果依赖项数组为空([]),那么回调函数只会在组件挂载时创建一次。
  • 记忆化的函数不应该有任何副作用,因为它们可能会在组件的整个生命周期内保持不变。

通过使用 useCallback,你可以更好地控制 React 组件的性能和渲染行为。

四、useMemo

useMemo 用于记忆化复杂计算的结果,确保只有在依赖项变化时才重新计算,从而避免不必要的性能开销。

基本用法:

const memoizedValue = useMemo(() => {
  // 这里是你的计算逻辑
  return someExpensiveComputation(a, b);
}, [a, b]); // 依赖项数组
  • 第一个参数:一个函数,它返回你想要记忆化的值。这个函数只有在依赖项变化时才会执行。
  • 第二个参数:依赖项数组。只有当这个数组中的某个元素发生变化时,函数才会重新执行,并且返回的新值会替换缓存的值。

特点

  • useMemo 仅在其依赖项变化时才重新计算。如果依赖项没有变化,它将返回缓存的值,而不是重新执行函数。
  • 它非常适合用于性能优化,尤其是在处理复杂的计算或大数据集时。

使用场景

  1. 避免重复的计算:当某个计算结果在多次渲染中保持不变时,使用 useMemo 可以避免不必要的计算。

  2. 优化渲染性能:通过缓存结果,减少渲染期间的计算量,提高渲染性能。

  3. 与依赖项解耦:当计算结果与组件的多个属性或状态相关联时,useMemo 可以确保只在相关依赖项变化时重新计算。

示例

假设你有一个组件,它根据传入的数值进行一些复杂的计算:

import React, { useMemo } from 'react';

function MyComponent({ a, b }) {
  // 使用 useMemo 来记忆化计算结果
  const result = useMemo(() => {
    // 假设这是一个昂贵的计算
    const expensiveComputation = (x, y) => {
      // ...进行一些计算...
      return x * y;
    };
    return expensiveComputation(a, b);
  }, [a, b]); // 当 a 或 b 变化时,重新计算

  return (
    <div>
      <p>The result is: {result}</p>
    </div>
  );
}

在这个示例中,result 只有在 ab 发生变化时才会重新计算。如果没有变化,它将返回缓存的值,从而避免重复的计算。

注意事项

  • 确保依赖项数组完整,否则可能会导致错误的缓存结果。
  • 不要将 useMemo 用于包含副作用的计算,它只适用于纯计算。
  • 使用 useMemo 可以提高性能,但也要小心不要过度使用,因为它可能会增加内存使用。

通过合理使用 useMemo,你可以有效地优化 React 组件的性能,减少不必要的计算和渲染。

useCallback 和 useMemo的区别:

  1. 记忆化内容

    • useCallback 记忆化函数。
    • useMemo 记忆化计算结果。
  2. 返回值

    • useCallback 返回一个函数。
    • useMemo 返回计算结果。
  3. 使用时机

    • useCallback 通常用于事件处理器或传递给子组件的函数。
    • useMemo 通常用于优化性能,避免在渲染期间进行昂贵的计算。
  4. 副作用

    • useCallback 的函数不应该包含副作用。
    • useMemo 的函数可以执行计算,但不应该包含副作用。
  5. 依赖项变化时的行为

    • 当依赖项变化时,useCallback 会重新创建函数。
    • 当依赖项变化时,useMemo 会重新执行计算函数。

示例

import React, { useMemo, useCallback } from 'react';

function MyComponent(a, b) {
  // 记忆化回调函数,避免子组件不必要渲染
  const handleClick = useCallback(() => {
    console.log('Clicked with', a, b);
  }, [a, b]);

  // 记忆化计算结果,避免重复计算
  const computedValue = useMemo(() => {
    return a * b;
  }, [a, b]);

  return (
    <div>
      <button onClick={handleClick}>Click me</button>
      <p>Computed Value: {computedValue}</p>
    </div>
  );
}

一边学习一边更新~~

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

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

相关文章

C++面向对象程序设计 - 函数库

C语言程序中各种功能基本上都是由函数来实现的&#xff0c;在C语言的发展过程中建立了功能丰富的函数库&#xff0c;C从C语言继承了些函数功能。如果要用函数库中的函数&#xff0c;就必须在程序文件中包含文件中有关的头文件&#xff0c;在不同的头文件中&#xff0c;包含了不…

RabbitMQ实践——交换器(Exchange)绑定交换器

在《RabbitMQ实践——交换器&#xff08;Exchange&#xff09;和绑定&#xff08;Banding&#xff09;》一文中&#xff0c;我们实验了各种交换器。我们可以把交换器看成消息发布的入口&#xff0c;而消息路由规则则是由“绑定关系”&#xff08;Banding&#xff09;来定义&…

GitLab教程(二):快速上手Git

文章目录 1.将远端代码克隆到本地2.修改本地代码并提交到远程仓库3.Git命令总结git clonegit statusgit addgit commitgit pushgit log 首先&#xff0c;我在Gitlab上创建了一个远程仓库&#xff0c;用于演示使用Gitlab进行版本管理的完整流程&#xff1a; 1.将远端代码克隆到本…

快速构建本地RAG聊天机器人:使用LangFlow和Ollama实现无代码开发

基于LangChain的快速RAG应用原型制作方法 还记得构建智能聊天机器人需要数月编码的日子吗&#xff1f; LangChain这样的框架确实简化了开发流程&#xff0c;但对非程序员来说&#xff0c;数百行代码仍然是一道门槛。 有没有更简单的方法呢&#xff1f; 图片由 Ravi Palwe 在…

数字政协:迈向智慧时代,开启政协工作新篇章

在信息化浪潮席卷全球的今天&#xff0c;数字技术不仅改变了我们的生活方式&#xff0c;也深刻影响着政治生态的变革。其中&#xff0c;“数字政协”的崛起&#xff0c;正是新时代政协工作创新发展的重要标志。那么&#xff0c;什么是数字政协&#xff1f;它又将如何助力政协工…

[图解]建模相关的基础知识-09

1 00:00:01,350 --> 00:00:03,780 首先&#xff0c;我们来看一下什么叫关系 2 00:00:05,370 --> 00:00:08,990 这个关系跟下面说的这些关系 3 00:00:09,000 --> 00:00:10,390 它不是一个东西 4 00:00:11,110 --> 00:00:14,950 比如说&#xff0c;我们UML类图上&…

门控循环单元GRU与长短期记忆网络LSTM

门控循环单元与长短期记忆网络 门控隐状态 问题提出&#xff1a;对于一个序列来说不是每个观察值都是同等重要想只记住相关的观察需要&#xff1a; 能关注的机制&#xff08;更新门&#xff09;能遗忘的机制&#xff08;重置门&#xff09; 第一个词元的影响至关重要。 我们…

使用vuejs3时,报错:Uncaught (in promise)

解决&#xff1a; vite.config.js里 import {fileURLToPath, URL} from node:urlimport {defineConfig} from vite import vue from vitejs/plugin-vue// https://vitejs.dev/config/ export default defineConfig({resolve: {alias: {: fileURLToPath(new URL(./src, import…

LeetCode | 520.检测大写字母

这道题直接分3种情况讨论&#xff1a;1、全部都为大写&#xff1b;2、全部都为小写&#xff1b;3、首字母大写其余小写。这里我借用了一个全是大写字母的串和一个全为小写字母的串进行比较 class Solution(object):def detectCapitalUse(self, word):""":type …

通过Vue3+高德地图的JS API实现市区地图渲染

效果图: 核心代码: <script setup>import { onMounted, onUnmounted } from vue;import AMapLoader from @amap/amap-jsapi-loader;import { message } from ant-design-vue;import school from @/assets/icons/school.svg;import enterprise from @/assets/icons/ent…

pytest + yaml 框架 -61.jenkins+allure+钉钉通知添加测试结果

前言 上一篇pytest + yaml 框架 -60.git+jenkins+allure+钉钉通知反馈 已经实现测试结果用钉钉通知。 本篇继续在钉钉通知里添加测试的汇总结果,此功能在pytest-yaml-yoyo v1.5.2版本上实现。 Environment Injector 插件 在运行完用例后会生成一个summary.json 文件,汇总…

JAVA小知识20:万字详解List与ArrayList

一、集合简介 1.1、什么是集合&#xff1f; 可同时存储多个元素的数据结构就是集合。 1.2、为什么要有集合&#xff1f; 我们可以使用数组同时存储多个元素&#xff0c;但是数组有个弊端。数组创建之后长度就会固定&#xff0c;如需扩容则需要手动扩容&#xff0c;我们需要…

【计算机视觉】人脸算法之图像处理基础知识(四)

图像的几何变换 图像的几何变换是指在不改变图像内容的前提下对图像的像素进行空间几何变换。主要包括图像的平移变换、镜像变换、缩放和旋转等。 1.插值算法 插值通常用来放缩图像大小&#xff0c;在图像处理中常见的插值算法有最邻近插值法、双线性插值法、二次立方、三次…

中小制造业工厂要不要上MES系统

MES系统的主要功能包括制造数据管理、计划排产管理、生产调度管理、库存管理、质量管理、人力资源管理、工作中心/设备管理、工具工装管理、采购管理、成本管理、项目看板管理、生产过程控制、底层数据集成分析、上层数据集成分解等。通过这些模块&#xff0c;MES为企业打造一个…

【网络安全学习】使用Kali做渗透情报收集-01-<域名信息主机信息>

1.收集开源情报 开源情报(Open Source Intelligence&#xff0c;OSINT)是指从各种公开的渠道中寻找和获取有价值的信息 如&#xff1a;互联网、媒体、社交网络、公共数据库等开源情报具有以下特点&#xff1a; - 丰富性&#xff1a;开源情报涵盖了各种类型和领域的信息 - 可…

【学习】什么样的软件测试项目适合做自动化测试

随着科技的发展和社会的进步, 软件行业也在不断地壮大和发展。在这个过程中&#xff0c;软件测试变得越来越重要&#xff0c;并且成为了保证软件质量的关键环节。而自动化测试作为软件测试的一种方法&#xff0c;在提高测试效率、降低人力成本等方面具有显著的优势。那么什么样…

SpringBoot集成mqtt上下线提醒功能设计

目录 1.首先安装emqx&#xff0c;去官网下载emqx压缩包&#xff0c;并且解压。 2.使用emqx start 命令启动emqx后台管理 3.下载mqttx调试工具&#xff0c;使用mqttx调试mqtt连接。下载地址:MQTTX下载-MQTTX官方版下载,下载完成直接打开&#xff0c;便可进行mqtt连接调试 4.…

超详解——Python 字典详解——小白篇

目录 1. 创建字典 示例&#xff1a; 2. 访问字典中的元素 示例&#xff1a; 3. 修改字典元素 示例&#xff1a; 4. 删除字典元素 示例&#xff1a; 5. 查找元素是否是字典的键 示例&#xff1a; 6. 标准类型操作符 获取字典长度 合并两个字典 7. 常用内置函数 k…

el-table表头修改文字或者背景颜色,通过header-row-style设置样式

方式一 <el-table :header-cell-style"{text-align: center}" />方式二 <template><el-table :header-cell-style"tableHeaderColor" /> </template> <script> export default {methods: {tableHeaderColor ({row, column…

socket收发数据的处理

1. TCP 协议是一种基于数据流的协议 Socket的Receive方法只是把接收缓冲区的数据提取出来,当系统的接收缓冲区为空,Receive方法会被阻塞,直到里面有数据。 Socket的Send方法只是把数据写入到发送缓冲区里,具体的发送过程由操作系统负责。当操作系统的发送缓冲区满了,Send方法会…