我需要useCallback当从子组件运行函数吗?

huangapple go评论73阅读模式
英文:

Do I need useCallback when running a function from a child component

问题

Should the hoc function handleDoIt() be wrapped in useCallback here?

const handleDoItCallback = useCallback(async () => {
  setStatus("Doing It...");
  await onDoIt();
  handleDidIt();
}, [onDoIt]);

Codesandbox Demo

英文:

I understand that we should consider useCallback when we care about ensuring referential equality is considered during parent component renders. However, I am not clear if I need it in the following scenario where the parent is actually processing a child function.

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

interface WrapperProps {
  children: ReactNode;
  onDoIt: () => Promise<void>;
}

type Status = "Do It" | "Doing It..." | "Did It";

export const Wrapper: React.FC<WrapperProps> = ({ children, onDoIt }) => {
  const [status, setStatus] = useState<Status>("Do It");

  const handleDidIt = () => {
    setStatus("Did It");
  };

  const handleDoIt = async () => {
    setStatus("Doing It...");
    await onDoIt();
    handleDidIt();
  };

  return (
    <>
      <button onClick={handleDoIt} disabled={status !== "Do It"}>
        {status}
      </button>
      <hr />
      {children}
    </>
  );
};

export default function App() {
  const [result, setResult] = useState<string>("");

  const doIt = (): Promise<void> => {
    return new Promise((resolve) => {
      window.setTimeout(() => {
        setResult("Done, thanks");
        return resolve();
      }, 1000);
    });
  };

  return (
    <Wrapper onDoIt={doIt}>
      <h1>Hello CodeSandbox</h1>
      <p>{result}</p>
    </Wrapper>
  );
}

Should the hoc function handleDoIt() be wrapped in useCallback here?

  const handleDoItCallback = useCallback(async () => {
    setStatus("Doing It...");
    await onDoIt();
    handleDidIt();
  }, [onDoIt]);

Codesandbox Demo

答案1

得分: -1

是的,它应该被包含在依赖项中,以及它使用的任何其他函数。

在这种情况下:

const handleDidIt = useCallback(() => {
    setStatus("Did It");
}, []);

然后在依赖项数组中包括:

const handleDoIt = useCallback(async () => {
    setStatus("Doing It...");
    await onDoIt();
    handleDidIt();
}, [onDoIt, handleDidIt]);

如果不这样做,那么handleDoIt可能会与最新的handleDidIt不一致。在这种情况下,这并不重要,因为它只是一个常量状态更新,但在更复杂的逻辑中可能会有影响。

最后,在父组件中:

const doIt = useCallback((): Promise<void> => {
    return new Promise((resolve) => {
        window.setTimeout(() => {
            setResult("Done, thanks");
            return resolve();
        }, 1000);
    });
});

值得注意的是,setStatus 不需要包含在任何依赖数组中,因为它始终保持稳定。

英文:

Yes it should be wrapped, as well as any other function it uses.

In this case:

const handleDidIt = useCallback(() =&gt; {
    setStatus(&quot;Did It&quot;);
}, []);

and then include in the deps array:

const handleDoIt = useCallback(async () =&gt; {
    setStatus(&quot;Doing It...&quot;);
    await onDoIt();
    handleDidIt();
  }, [onDoIt, handleDidIt]);

If you do not do this, then handleDoIt can fall out-of-date with the latest handleDidIt. In this case, it doesn't matter as it's just a constant state update, but it can with more complex logic.

Lastly, in the parent:

const doIt = useCallback((): Promise&lt;void&gt; =&gt; {
    return new Promise((resolve) =&gt; {
      window.setTimeout(() =&gt; {
        setResult(&quot;Done, thanks&quot;);
        return resolve();
      }, 1000);
    });
  });

Notably, setStatus does not need to be included in either dependency array because it is always guaranteed to be stable.

huangapple
  • 本文由 发表于 2023年6月8日 02:42:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76426204.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定