当前位置: 首页 > article >正文

react 中 useCallback Hook 作用

一、性能优化

1. 防止函数的重复创建

1.1 函数组件重新渲染问题

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

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)的函数,只有在依赖项发生变化时,才会重新创建该函数。

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 结合时的作用

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

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`可以解决这个问题:

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 代码示例

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`的依赖项(这里没有依赖项,所以函数只会创建一次)变化时,才会重新创建该函数。这确保了数据获取操作(副作用)不会因为函数的不必要重新创建而频繁触发。


http://www.kler.cn/a/396229.html

相关文章:

  • 浅层神经网络
  • c#————委托Action使用例子
  • 昆明华厦眼科医院举办中外专家眼科技术研讨会
  • 基于Spring Boot的在线性格测试系统设计与实现(源码+定制+开发)智能性格测试与用户个性分析平台、在线心理测评系统的开发、性格测试与个性数据管理系统
  • 基于微信小程序的平安驾校预约平台的设计与实现(源码+LW++远程调试+代码讲解等)
  • BILSTM法律网站用户提问自动分类
  • STM32学习笔记----时钟体系
  • 第9章 DIV+CSS布局作业
  • AGI自学分享,简单有用的理论与实践
  • 【pandas】常用方法积累
  • OceanBase 升级过程研究(4.2.1.6-4.2.1.8)
  • 【CSS问题】margin塌陷
  • Hadoop 学习心得
  • 开源项目低代码表单设计器FcDesigner扩展自定义组件
  • Cadence安装
  • 跨域请求解决的核心
  • pytorch环境问题以及探索Dataloader的数据格式
  • MongoDB索引操作和执行计划Explain()详解
  • 课程管理|基于springboot+vue的在线课程管理系统(源码+数据库+文档)
  • unity3d————特殊文件夹
  • Go语言中的类型断言
  • Python连接Mysql、Postgre、ClickHouse、Redis常用库及封装方法
  • 嵌入式交叉编译:glib(未成功)
  • React状态管理之Redux
  • TVBox 网络接口
  • Go-RPC框架分层设计