理解 Reactjs 中的 useCallback

理解 Reactjs 中的 useCallback
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}"></childcomponent>
</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}"></slowcomponent>
</div>
  );
};

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

// Intentially making the component slow
  for (let i = 0; i Click me in SlowComponent;
});

export default App;

何时使用 usecallback

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

buy me a coffee

以上就是理解 Reactjs 中的 useCallback的详细内容,更多请关注其它相关文章!