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

一、useEffect

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

基本用法

useEffect 接受两个参数:

  1. Effect 函数:这是一个包含副作用操作的函数,它将在组件渲染到屏幕后执行。
  2. 依赖项数组:这个数组定义了 effect 函数依赖的组件状态或属性。如果数组中的值发生变化,effect 函数将重新执行。
示例:
javascript 复制代码
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 可以返回一个函数,这个函数在组件卸载或重新渲染前执行,用于清理副作用。

示例:
javascript 复制代码
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 的第二个参数。

示例:
javascript 复制代码
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

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

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

模拟 componentWillUnmount

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

示例:
javascript 复制代码
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 将负责重新渲染组件。
示例:
javascript 复制代码
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 是更新这个状态的函数。

使用函数更新状态

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

示例:
javascript 复制代码
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 多次来分别创建它们。

示例:
javascript 复制代码
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 会返回同一个函数引用,只要依赖项数组中的值没有变化。这在性能优化中非常有用,特别是当你希望避免在每次渲染时创建新的函数实例,或者在子组件中使用这些函数时。

基本用法

javascript 复制代码
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 用于记忆化复杂计算的结果,确保只有在依赖项变化时才重新计算,从而避免不必要的性能开销。

基本用法:

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

特点

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

使用场景

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

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

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

示例

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

javascript 复制代码
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 会重新执行计算函数。

示例

javascript 复制代码
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>
  );
}

一边学习一边更新~~

相关推荐
辻戋1 小时前
从零实现React Scheduler调度器
前端·react.js·前端框架
徐同保1 小时前
使用yarn@4.6.0装包,项目是react+vite搭建的,项目无法启动,报错:
前端·react.js·前端框架
Qrun2 小时前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp2 小时前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.3 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
TeleostNaCl5 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫6 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友6 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理8 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻8 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js