【问题标题】:Why default value in functional React component gets updated after render?为什么功能性 React 组件中的默认值会在渲染后更新?
【发布时间】:2021-02-20 00:50:00
【问题描述】:

我很难理解为什么我在这个 React 组件的控制台中记录了不同的值:

const MyComponent = () => {

  // Initialise data with a random value:
  const [data, setData] = React.useState(
    () => {
      const data = _.sampleSize(_.range(5), 3)
      // Print data on initialisation:
      console.log('init data in default:', data)
      return data
    }
  )

  React.useEffect(() => {
    // Print data after the component is rendered:
    console.log('init data after render:', data)
  })

  return (
    <div>{data}</div>
  );
};

控制台的输出是:

[Log] init data in default: – [0, 3, 1] (3)
[Log] init data after render: – [2, 1, 3] (3)

并且组件被渲染到:&lt;div&gt;213&lt;/div&gt;

但是为什么值不同呢?

我的理解是在组件渲染之前,调用useState下的函数。函数返回的值赋值给datadata的值用于在屏幕上渲染组件。 useState下的函数只调用一次,我们从不调用setData,所以值应该是一样的。我错过了什么?

UPD:我尝试创建一个代码sn-p,这是我第一次使用codesandbox,所以如果它不起作用请告诉我: https://codesandbox.io/s/jovial-glade-9jm75?file=/src/App.js

【问题讨论】:

  • 这与&lt;StrictMode&gt; 有关。从您的 index.js 中删除它,问题就会消失。但我还没有把所有的部分放在一起给出一个完整的答案。
  • 肯定是StrictMode 在工作中,它调用了两次渲染,因此调用了两次useState,由于sampleSize 返回随机元素,第二次渲染中的随机选择就是useEffect 拾取的.
  • 嗯,但是为什么console.log('init data in default:', data) 只打印一次呢?我想我至少应该看到React.useState下的函数被调用了两次。
  • React 17,React 会自动修改 console.log() 等控制台方法,以在第二次调用生命周期函数时使日志静音。

标签: javascript reactjs lodash


【解决方案1】:

Strict mode 导致 React 运行组件两次,以检测各种可能的不安全代码部分。这有点像有限的运行时 linter。

在里面:

从 React 17 开始,React 会自动修改 console.log() 等控制台方法,以在第二次调用生命周期函数时静默日志。

第一次调用组件时,useState 调用中的console.log 运行,记录生成的第一个数据。

第一次调用没有完全渲染; useEffect 永远不会运行。相反,React 会再次运行该组件来检查是否存在不一致。在第二次运行时,useState 中的 console.log 被抑制。

然后,稍后,在第二次运行时,组件真正正确地完成了渲染,并且它的效果挂钩运行,它记录了之前生成的数据(但未显示在控制台中)。

Here's a post describing a very similar issue.

【讨论】:

  • 好了,谜底就这样解开了。但这是非常出乎意料的行为。您没有看到组件被重新渲染并且输出不同。很高兴知道!谢谢你的详细解答
猜你喜欢
  • 2020-03-30
  • 1970-01-01
  • 2021-07-25
  • 2022-11-29
  • 1970-01-01
  • 1970-01-01
  • 2020-07-28
  • 2021-01-14
  • 1970-01-01
相关资源
最近更新 更多