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>
  );
}

一边学习一边更新~~

相关推荐
musk12126 分钟前
electron 打包太大 试试 tauri , tauri 安装打包demo
前端·electron·tauri
翻滚吧键盘35 分钟前
js代码09
开发语言·javascript·ecmascript
万少1 小时前
第五款 HarmonyOS 上架作品 奇趣故事匣 来了
前端·harmonyos·客户端
OpenGL1 小时前
Android targetSdkVersion升级至35(Android15)相关问题
前端
rzl021 小时前
java web5(黑马)
java·开发语言·前端
Amy.Wang1 小时前
前端如何实现电子签名
前端·javascript·html5
海天胜景1 小时前
vue3 el-table 行筛选 设置为单选
javascript·vue.js·elementui
今天又在摸鱼1 小时前
Vue3-组件化-Vue核心思想之一
前端·javascript·vue.js
蓝婷儿2 小时前
每天一个前端小知识 Day 21 - 浏览器兼容性与 Polyfill 策略
前端
百锦再2 小时前
Vue中对象赋值问题:对象引用被保留,仅部分属性被覆盖
前端·javascript·vue.js·vue·web·reactive·ref