gpt4 book ai didi

javascript - 组件本身是否应该防止不必要的 useEffect() 调用?

转载 作者:行者123 更新时间:2023-12-05 00:36:57 25 4
gpt4 key购买 nike

使用 useEffect()正确地有时并不那么容易。想象一下,我们有一个使用 Counter 的简单应用程序零件:

import { useState, useEffect } from 'react';

const Counter = ({ onOdd, onEven }) => {
const [count, setCount] = useState(0);

useEffect(
() => {
console.log('Inside useEffect()');

if (count % 2 === 0) {
onEven(count);
} else {
onOdd(count);
}
},
[count, onOdd, onEven]
);

return (
<button
type="button"
onClick={() => setCount(count => count + 1)}
>
{count}
</button>
);
}

const App = () => {
const [isDarkMode, setIsDarkMode] = useState(false);

return (
<div style={{
backgroundColor: isDarkMode ? 'black' : 'white',
}}>
<Counter
onOdd={count => console.log(`Odd count: ${count}`)}
onEven={count => console.log(`Even count: ${count}`)}
/>
<button
type="button"
onClick={() => setIsDarkMode(isDarkMode => !isDarkMode)}
>
Toggle dark mode
</button>
</div>
);
}

export default App;
该应用程序做了两件事:
  • 它包括一个 Count将计数器加 1 的按钮。此组件允许注入(inject)两个函数:onOddonEven .每当计数器更改时,onOddonEven被称为,取决于计数器......是奇数还是偶数。
  • 还有一个暗模式切换。我添加它的唯一目的是有一些导致 Counter 的东西。除了更改 count 之外的其他原因重新渲染.

  • 现在,该应用程序有一个怪癖 - 每当我们切换暗/亮模式时, onOddonEven正在被调用。这是错误的,但可以理解——我们在每次渲染时都创建了新函数,所以 useEffect()正在被调用。
    我可以想到 4 种方法来解决此问题:
  • 删除 onOddonEven来自 useEffect()依赖关系。它将修复该行为,但它被认为是一个问题。 linter 会提示它,因为我们正在失去数据完整性。理论上,如果我们真的改变这些回调,他们应该重新运行,对吧?那将是“ react 方式”。
  • 将回调函数移到 App 之外组件:
  • const onOdd = count => console.log(`Odd count: ${count}`);
    const onEven = count => console.log(`Even count: ${count}`);

    const App = () => {
    // ...
    return (
    // ...
    <Counter
    onOdd={onOdd}
    onEven={onEven}
    />
    // ...
    );
    }
    这是一个很好且快速的解决方案,但这只是因为我们没有在这些回调中使用钩子(Hook)或状态。如果我们这样做了怎么办?
  • 使用 useCallback()App组件:
  • const App = () => {
    // ...

    const onOdd = useCallback(
    count => console.log(`Odd count: ${count}`),
    []
    );

    const onEven = useCallback(
    count => console.log(`Even count: ${count}`),
    []
    );

    return (
    // ...
    <Counter
    onOdd={onOdd}
    onEven={onEven}
    />
    // ...
    );
    }
  • 内存 Counter 中的回调函数零件。如果我们有数千个组件使用 Counter组件,它仍然意味着只需要一个地方来存储这些功能。我不确定这是否有意义。

  • React 大师如何解决这个问题?我想让示例尽可能简单,因此选项 #2 将完美运行,并且可能更可取。但是,如果我们需要将这些回调保存在 App 中怎么办?零件?
    是否总是由父组件负责记住它传递给子组件的所有回调?如果是这样,是否始终使用 useCallback() 记住作为 Prop (可能还有任何其他对象)传递的所有函数是一种公认​​的模式?或 useMemo() ?

    最佳答案

    我不是一个真正的 React Guru,但我认为前三种方法都有它们的最佳位置,第四种没有意义。唯一要小心的是第一个,因为从 deps 中删除函数可能会导致过时状态问题,所以如果你知道你在做什么,你可能会抑制 lint warn (我有时会这样做并且知道很多其他人会这样做正如这里已经讨论过的那样 https://github.com/facebook/react/issues/14920 ),否则最好避免这种方法。
    每当你有纯函数时,第 2 点是首选,总是尝试将你的纯函数放在 React 组件之外,放在其他一些文件夹中,如 utils、misc 等......
    根据第 3 点,这是处理在 React 组件中声明的函数的首选方式,请始终使用 *useCallback* 来内存它们。 (或 useMemo 如果您需要在返回函数之前执行计算),并且在父组件中这样做并没有什么不好。如果您发现自己有几十个或数百个并且担心代码污染,请考虑使用自定义钩子(Hook)让您巧妙地组织代码,您可以在 App 组件中创建一个自定义钩子(Hook),如 useMemoizedHandlers,您可以在其中创建和内存所有处理程序并使用就如:

    const { 
    handler1,
    handler2,
    handler3
    } = useMemoizedHandlers()

    关于javascript - 组件本身是否应该防止不必要的 useEffect() 调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71812632/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com