【问题标题】:How does React useState and useCallback hook work when useCallback lacks dependencies当 useCallback 缺少依赖时 React useState 和 useCallback hook 是如何工作的
【发布时间】:2019-11-16 10:17:33
【问题描述】:

我最近在学习 react-hook。我在实践过程中遇到了一个让我无法理解的问题。

import React, { useState, useCallback } from 'react';
const set = new Set();

function Demo() {
  const [count, setCount] = useState(0);

  const changeValue = useCallback(() => {
    setCount(count + 1);
  }, []); 

  set.add(count);
  console.log('size: ', set.size);

  return(
    <div>
      <p>Hello React Hook</p>
      <p>{count}</p>
      <button onClick={changeValue}>count++</button>
    </div>
  )
}

export default Demo;

// If you click the button multiple times, the output is:
// size: 1
// size: 2
// size: 2

我使用 react-hook 编写了一个计时器。正如我所料,显示的 count 值始终为 1,因为我没有使用 count 作为 useCallback 的依赖项。

但我无法理解的是console.log('size: ', set.size) 只打印了三遍,为什么?每次点击count++按钮,都会导致Demo函数重新执行。所以每次我点击按钮时,不应该console.log('size: ', set.size)会被执行吗?但实际上它只执行了 3 次。

为什么size 保持 2 不变?我知道setCount 每次都会替换一个新的count,所以size 应该不会增加?

请帮我解答我的疑惑,非常感谢。

你可以测试我的代码here

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    Demo 组件将在其状态更改时重新渲染。因此,当您将计数状态添加到集合时,它将具有大小 1:

    set.add(count); // 0 in initial render, size is 1
    

    现在,当您单击按钮时,它将使用由 react 记忆的回调 useCallback。这意味着它将首先检查是否有缓存值。因此,在第一次单击时,它没有缓存值。因此它调用它的回调来设置(更新)计数状态。现在,count 为 1,您还将 count 添加到集合中。

    set.add(count); // 1 in first click, size is 2
    

    在接下来的点击中,useCallaback 已经缓存了计数值,但您没有在 useCallback 钩子的第二个参数中设置计数,因此它只会返回缓存值 1 - 计数状态。它会永远从这里返回。我再重复一遍,这次设置的大小是 2。

    将计数状态放入第二个参数时,您应该注意变化:

      const changeValue = useCallback(() => {
        setCount(count + 1);
      }, [count]); // we watch it on every click
    

    现在,每次单击按钮时,您都会看到变化的值。


    另请注意:不要混淆changeValue 不会在以下点击中被调用。这每次都会调用 useCallback 但它只是不更新​​状态:

      const changeValue = useCallback(() => {
        console.log('clicked') // logged every time on button click
        setCount(count + 1); // count state is not being watched, 
         // setCount won't update the count on following clicks
         // once it caches the state.
      },[]); // need to watch state here to update the state
    

    【讨论】:

    • useCallback 用于记忆函数。在这种情况下使用回调是没有意义的,因为它的依赖关系会在每次函数重新渲染时发生变化。可以参考setCount中之前的状态,使useCallback没有依赖
    • @EduardMukans OP 正在学习钩子并试图了解 useCallback 钩子的工作原理。这就是这里的解释。
    • @Bhojendra Rauniyar 我明白你说的,但我还是有问题。第一次点击按钮后,count的值开始被缓存,所以第二次点击时count保持不变。但是为什么第二次点击还是打印size:2呢?
    • 因为计数状态保持不变。 Demo 函数不会重新渲染并且 set.add(count) 不会被调用。对于您的查询,为什么第二次单击仍然打印 size: 2 是因为它在缓存后第一次返回。之后它将不会被调用。
    • @Bhojendra Rauniyar 是的,演示函数不会重新渲染,因为计数状态保持不变。那么为什么它仍然在第二次点击时打印 size: 2 呢?我不太了解“它在缓存后第一次返回”。能麻烦你解释一下吗?
    猜你喜欢
    • 1970-01-01
    • 2021-06-17
    • 2023-02-21
    • 2022-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-02
    • 2021-08-26
    相关资源
    最近更新 更多