首页 > web前端 > js教程 > 理解 Reactjs 中的 useCallback

理解 Reactjs 中的 useCallback

Linda Hamilton
发布: 2024-10-27 01:51:03
原创
987 人浏览过

Understanding useCallback in Reactjs
useCallback 钩子会记住函数本身,而不是它的返回值。 useCallback 缓存函数引用

组件内部声明的函数会在每次渲染时重新创建,类似于变量。不同之处在于,它每次都会使用不同的参考进行渲染。所以,

  • 依赖于此函数的 useEffect 将在每次渲染时再次执行。
  • 子组件也会发生类似的情况。

依赖于此函数的 useEffect 将在每次渲染时再次执行:

import React, { useState, useEffect, useCallback } from 'react';

// Parent Component
const ParentComponent = () => {
  const [count, setCount] = useState(0);
  const [text, setText] = useState("");

  // Function declared inside the component
  const handleClick = () => {
    setCount(count + 1);
  };

  // useEffect depending on handleClick
  useEffect(() => {
    console.log("handleClick changed, running useEffect");
  }, [handleClick]);

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

// Child Component
const ChildComponent = React.memo(({ handleClick }) => {
  console.log("ChildComponent re-rendered");
  return <button onClick={handleClick}>Child Increment</button>;
});

export default ParentComponent;
登录后复制

子组件也会发生类似的情况:

当我们将一个具有昂贵或“慢”渲染逻辑的组件作为另一个组件的子组件时,每次父组件渲染时,其所有子组件也会重新渲染。

为了防止这些不必要的重新渲染,我们可以使用 React.memo。这个高阶组件会缓存子组件,确保它仅在其 props 实际发生变化时才重新渲染。然而,当将函数作为 props 传递时,有一个微妙的问题,这会导致子进程重新渲染,即使它不应该重新渲染。

函数引用的问题

想象一下我们有一个 SlowComponent 作为 App 的子组件。在 App 中,我们有一个状态会在按钮单击时发生变化,从而触发 App 的重新渲染。尽管我们没有更改 SlowComponent 的 props,但它仍然会在每次点击时重新渲染。

为什么?在每次渲染时,handleClick 函数都会使用新的引用重新创建,React 将其解释为更改后的 prop,导致 SlowComponent 重新渲染。为了解决这个问题,我们使用 useCallback 钩子来跨渲染缓存函数的引用。

使用 useCallback 的解决方案

通过将handleClick包装在useCallback中,我们告诉React仅在特定依赖项发生变化时重新创建它。语法如下:

const cachedFn = useCallback(fn, [dependencies]);
登录后复制
  • fn:这是您要缓存的函数定义。它可以接受参数并返回任何值。
  • 依赖项:这是一个依赖项数组。如果任何依赖项发生变化,React 将重新创建 fn。 在第一次渲染时,React 创建并缓存该函数。在后续渲染中,只要依赖项没有改变,就会返回缓存的函数,确保它有一个稳定的引用。

在我们的示例中应用 useCallback
让我们看看如何使用 useCallback 来优化我们的 App 组件:

import React, { useState, useCallback } from "react";

const App = () => {
  const [count, setCount] = useState(0);
  const [value, setValue] = useState("");

  // Wrapping handleClick with useCallback to cache its reference
  const handleClick = useCallback(() => {
    setValue("Kunal");
  }, [setValue]);

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

const SlowComponent = React.memo(({ handleClick }) => {

// Intentially making the component slow
  for (let i = 0; i < 1000000000; i++) {}
  console.log("SlowComponent re-rendered");
  return <button onClick={handleClick}>Click me in SlowComponent</button>;
});

export default App;
登录后复制

何时使用 useCallback

  • 当您为组件内的元素定义了事件处理程序时,请将它们包装在 useCallback 中,以避免不必要地重新创建事件处理程序。
  • 当您在 useEffect 中调用函数时,通常会将该函数作为依赖项传递。为了避免在每次渲染时不必要地使用 useEffect,请将函数定义包装在 useCallback 中。
  • 如果您正在编写自定义钩子,并且它返回一个函数,建议将其包装在 useCallback 中。因此,用户无需担心优化钩子 - 相反,他们可以专注于自己的代码。

Understanding useCallback in Reactjs

以上是理解 Reactjs 中的 useCallback的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板