React 18,useEffect 在挂载时被调用两次

React 18, useEffect is getting called two times on mount

我有一个计数器并在 useEffect 中设置了 console.log 以记录我状态中的每个更改,但是 useEffect 在挂载时被调用了两次。我正在使用 React v18.0.0。这是我的项目的 CodeSandbox 和下面的代码:

import  { useState, useEffect } from "react";

const Counter = () => {
  const [count, setCount] = useState(5);

  useEffect(() => {
    console.log("rendered");
    console.log(count);
  }, [count]);

  console.log("rendered");

  return (
    <div>
      <h1> Counter </h1>
      <div> {count} </div>
      <button onClick={() => setCount(count + 1)}> click to increase </button>
    </div>
  );
};

export default Counter;

当您处于 strict mode in development 时,这是 React 18 本身的行为。核心团队正在尝试实现此功能,即使在 unmount 之后我们也可以保留组件的 stateuseEffect 被调用两次与此功能有关。以下是他们在 documentation:

中所说内容的概述

In the future, we’d like to add a feature that allows React to add and remove sections of the UI while preserving state.

With Strict Mode starting in React 18, whenever a component mounts in development, React will simulate immediately unmounting and remounting the component.

On the second mount, React will restore the state from the first mount. This feature simulates user behavior such as a user tabbing away from a screen and back, ensuring that code will properly handle state restoration.

在大多数情况下,您不必担心它,因为它会在 production 后消失。核心团队正在讨论未来如何处理这种行为。要了解更多信息,您可以观看此 YouTube Video.

但是,如果需要,您可以使用布尔值 ref 使用 useRef 添加一些额外的控件,例如在您的情况下:

import  { useState, useEffect, useRef } from "react";

const Counter = () => {
  const firstRenderRef = useRef(true);
  const [count, setCount] = useState(5);

  useEffect(() => {
    if(firstRenderRef.current){
      firstRenderRef.current = false;
      return;
    }
    console.log("rendered", count);
  }, [count]);

  return (
    <div>
      <h1> Counter </h1>
      <div> {count} </div>
      <button onClick={() => setCount( count + 1 )}> click to increase </button>
    </div>
  );
};

export default Counter;