【问题标题】:React: useEffect vs useMemo vs useState反应:useEffect vs useMemo vs useState
【发布时间】:2019-10-14 07:16:07
【问题描述】:

我试图在网上找到一个简洁的答案,但没有运气。

以下关于useEffectuseMemouseState 之间的区别是否正确?

  • 两者 useStateuseMemo 都会在渲染中记住一个值。不同之处在于:
    • useMemo 不会导致重新渲染,而 useState
    • useMemo 仅在其依赖项(如果有)发生更改时运行,而 setSomeStateuseState 返回的第二个数组项)没有这样的依赖项数组
  • 两者 useMemouseEffect 仅在它们的依赖关系发生变化(如果有)时运行。不同之处在于:
    • useEffect 运行之后渲染发生,而useMemo 运行之前

我遗漏了任何其他关键差异吗?

【问题讨论】:

标签: javascript reactjs react-hooks


【解决方案1】:

您的观点基本正确,稍作澄清:

useState 导致调用 setState 方法时重新渲染(返回数组中的第二个元素)。它没有 useMemo 或 useEffect 等任何依赖项。

useMemo 仅在其依赖数组中的元素发生更改时重新计算一个值(如果没有依赖项 - 即数组为空,它将只重新计算一次)。如果数组被遗漏,它将在每次渲染时重新计算。调用该函数不会导致重新渲染。它还运行组件的渲染期间,而不是之前。

useEffect 在每次渲染后调用 ,如果其依赖数组中的元素已更改或数组被遗漏。如果数组为空,它只会在初始挂载时运行一次(如果返回清理函数则卸载)。

您可以随时查看Hooks API Reference,我认为这是一个非常可靠的文档

【讨论】:

  • 我很好奇的是声明常量的根本区别:ts const foo = useMemo(factoryForCreatingConstant, []); // vs const [bar] = useState(factoryForCreatingConstant); 两者在功能上似乎是相同的。
  • 你是对的,如果你像这样使用它,它们看起来在功能上是相同的。 useMemo 仅在依赖数组更改时才重新计算,在这种情况下它永远不会更改(因为数组为空)。我编辑了我的帖子以考虑不传递依赖数组和传递空数组之间的区别。使用useState,您可以获得setState 方法作为第二个数组元素,并且可以手动触发重新渲染,而 useMemo 只会在其依赖关系发生变化时重新计算
  • FWIW,我真的很好奇定义组件初始化常量,这就是我添加此评论的原因。如果您对讨论感兴趣,我最终会posting a question
  • @NoamaanMulla useMemouseEffect 有不同的用例(前者在渲染期间运行,后者在渲染之后运行 - 如上所述)。在某些情况下,它们会产生非常相似/相同的结果(请参阅此答案stackoverflow.com/a/68201925/10320683
【解决方案2】:
  • useEffect(callback, [dependency])的返回值为void,在render()之后执行。
  • useMemo(callback, [dependency]) 的返回值不是void,而是记忆值,它在render() 期间执行。

useEffect() 在以下情况下可以进行与 useMemo() 相同的优化:

  • 昂贵计算中使用的状态变量(即 count1)是 useEffect 的唯一依赖项。
  • 当我们不介意将昂贵的计算值存储在状态变量中时。
const [count1, setCount1] = useState(0);
const [expensiveValue, setExpensiveValue] = useState(null);
useEffect(() => {
    console.log("I am performing expensive computation");
    setExpensiveValue(((count1 * 1000) % 12.4) * 51000 - 4000);
  }, [count1]);   
  • 唯一的区别是,useEffect() 在render() 之后使昂贵的计算值可用,而 useMemo() 在render() 期间使该值可用。
  • 大多数情况下这无关紧要,因为如果已计算出该值以在 UI 中呈现,useEffect()useMemo() 都会在浏览器完成绘制之前使该值可用。

【讨论】:

    【解决方案3】:

    useMemo 用于记忆属于组件但不一定属于组件状态的计算/值,例如验证,依赖组件且必须返回值的方法;

      const validEmail = React.useMemo(() => validateEmail(email), [email])
      /* Now use 'validEmail' variable across the component, 
         whereas 'useEffect' return value is void and only used for unmounting duties, 
         like unsubscribing from subscription e.g. removeInterval*/
    

    from docs:

    请记住,传递给 useMemo 的函数在渲染期间运行。不要在那里做任何你在渲染时通常不会做的事情。比如副作用属于useEffect,而不是useMemo。


    useEffect Side effects:

    突变、订阅、计时器、日志记录和 其他副作用

    setState's setTimeout's setInterval'ref 分配、API 调用或任何不执行繁重计算的东西都属于这里。

    还请记住,优化是有代价的,因此 React 建议仅在需要记忆/优化时使用 useMemo,而在其他情况下,在必要时使用 useEffect

    您可以依赖 useMemo 作为性能优化,而不是语义保证。

    未来,React 可能会选择“忘记”一些之前记忆的内容 值并在下一次渲染时重新计算它们,例如释放内存 离屏组件。编写您的代码,使其在没有 useMemo - 然后添加它以优化性能。


    [state, setState] = useState() that is 更新在重新渲染期间保持稳定的给定状态变量,并调用附加到它的setState 触发重新渲染。这个钩子的用途和上面两个钩子没有太大关系。

    【讨论】:

      猜你喜欢
      • 2019-09-25
      • 2021-05-17
      • 1970-01-01
      • 2023-04-03
      • 2021-08-02
      • 2021-09-06
      • 2023-02-01
      • 1970-01-01
      • 2021-04-19
      相关资源
      最近更新 更多