react 中 useCallback Hook 作用

一、性能优化

1. 防止函数的重复创建

1.1 函数组件重新渲染问题

在 React 函数组件中,每次组件重新渲染时,内部的函数都会被重新创建。

javascript 复制代码
import React from "react";



const ParentComponent = () => {

  // 每次ParentComponent重新渲染,handleClick函数都会重新创建

  const handleClick = () => {

    console.log("Button clicked");

  };



  return <ChildComponent onClick={handleClick} />;

};



const ChildComponent = React.memo(({ onClick }) => {

  return <button onClick={onClick}>Click me</button>;

});

1.2 useCallback 的解决方案

`useCallback`可以用来解决这个问题。它会返回一个记忆化(memoized)的函数,只有在依赖项发生变化时,才会重新创建该函数。

javascript 复制代码
import React, { useCallback } from "react";



const ParentComponent = () => {

  // 只有在依赖项(这里没有依赖项,所以只会创建一次)改变时,handleClick才会重新创建

  const handleClick = useCallback(() => {

    console.log("Button clicked");

  }, []);



  return <ChildComponent onClick={handleClick} />;

};



const ChildComponent = React.memo(({ onClick }) => {

  return <button onClick={onClick}>Click me</button>;

});

2. 优化组件渲染树

2.1 复杂组件结构中的性能影响

在大型应用中,组件树可能非常复杂,存在多层嵌套的组件关系。当父组件重新渲染时,如果不进行优化,可能会引发大量子组件的不必要渲染,导致性能下降。`useCallback`通过稳定函数引用,减少了子组件重新渲染的连锁反应。

2.2 示例场景

假设存在一个多层级的表单组件,其中包含多个输入字段和相关的验证函数。当表单中的某个输入字段变化导致父组件重新渲染时,如果不使用`useCallback`,所有依赖这些验证函数的子组件都可能重新渲染。使用`useCallback`来包裹这些验证函数后,只有当验证函数的依赖项(如验证规则)发生变化时,函数引用才会改变,从而稳定了子组件的渲染行为。

二、依赖管理与副作用控制

1. 精确的依赖管理

1.1 与 useEffect 结合时的作用

例如:当一个副作用函数依赖于一个外部函数时,如果不进行处理,每次组件重新渲染可能会导致副作用函数被重新执行,因为外部函数的引用在每次渲染时可能不同。

javascript 复制代码
import React, { useEffect, useState } from "react";



const ComponentWithEffect = () => {

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



  // 模拟一个外部函数,每次组件重新渲染都会重新创建

  const externalFunction = () => {

    return count * 2;

  };



  useEffect(() => {

    const result = externalFunction();

    console.log("Effect with result:", result);

  }, [externalFunction]);



  return (

    <div>

      Count: {count}{" "}

      <button onClick={() => setCount(count + 1)}>Increment</button>

    </div>

  );

};

在上述代码中,`externalFunction`的重新创建导致`useEffect`的依赖项不断变化,从而使副作用函数在每次组件重新渲染时都被执行。通过`useCallback`可以解决这个问题:

javascript 复制代码
import React, { useEffect, useState, useCallback } from "react";



const ComponentWithEffect = () => {

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



  // 使用useCallback来记忆化externalFunction,只有count变化时才会重新创建

  const externalFunction = useCallback(() => {

    return count * 2;

  }, [count]);



  useEffect(() => {

    const result = externalFunction();

    console.log("Effect with result:", result);

  }, [externalFunction]);



  return (

    <div>

      Count: {count}{" "}

      <button onClick={() => setCount(count + 1)}>Increment</button>

    </div>

  );

};

现在,`externalFunction`只有在`count`(依赖项)变化时才会重新创建,`useEffect`的副作用函数也只会在`externalFunction`真正改变时被执行,实现了更精确的依赖管理。

2. 副作用的触发控制

2.1 避免不必要的副作用执行

例如:在一个数据获取的场景中,如果获取数据的函数由于不必要的重新创建而频繁触发,可能会对服务器造成不必要的负载,并浪费用户的网络资源。

2.2 代码示例

javascript 复制代码
import React, { useEffect, useState, useCallback } from "react";



const DataFetchingComponent = () => {

  const [data, setData] = useState(null);



  // 数据获取函数,如果不进行优化,可能会频繁触发

  const fetchData = useCallback(() => {

    fetch("https://example.com/api/data")

      .then((response) => response.json())

      .then((jsonData) => setData(jsonData));

  }, []);



  useEffect(() => {

    fetchData();

  }, [fetchData]);



  return (

    <div>{data ? <pre>{JSON.stringify(data)}</pre> : "Loading data..."}</div>

  );

};

在这个例子中,`fetchData`函数使用`useCallback`进行优化,只有在`fetchData`的依赖项(这里没有依赖项,所以函数只会创建一次)变化时,才会重新创建该函数。这确保了数据获取操作(副作用)不会因为函数的不必要重新创建而频繁触发。

相关推荐
好开心338 分钟前
javaScript交互补充(元素的三大系列)
开发语言·前端·javascript·ecmascript
小孔_H24 分钟前
Vue3 虚拟列表组件库 virtual-list-vue3 的使用
前端·javascript·学习·list
jokerest12332 分钟前
web——upload-labs——第五关——大小写绕过绕过
前端·后端
钢铁小狗侠1 小时前
前端(3)——快速入门JaveScript
前端
咔咔库奇1 小时前
CSS基础知识04
前端·css
Black蜡笔小新1 小时前
无插件H5播放器EasyPlayer.js网页web无插件播放器选择全屏时,视频区域并没有全屏问题的解决方案
前端·javascript·音视频
Augenstern、2 小时前
vue3 element el-table实现表格动态增加/删除/编辑表格行,带有校验规则
前端·javascript·vue.js
A黄俊辉A2 小时前
electron安装遇到的问题
前端·javascript·electron
lvbb662 小时前
ES6更新的内容中什么是proxy
前端·ecmascript·es6
痕忆丶2 小时前
鸿蒙北向开发 : hdmfs-分布式文件系统
前端