javascript - 为什么使用 Hooks 的 ReactJS 组件会根据开发者控制台是否打开而呈现一次或两次?

标签 javascript reactjs react-hooks codesandbox

以下代码在 codesandbox.io 网站的控制台(该版本使用 StrictMode )和下面的代码片段中同时打印两次( 不是 使用 StrictMode ):

const { useState, useEffect } = React;

function useCurrentTime() {
  const [timeString, setTimeString] = useState("");

  useEffect(() => {
    const intervalID = setInterval(() => {
      setTimeString(new Date().toLocaleTimeString());
    }, 100);
    return () => clearInterval(intervalID);
  }, []);

  return timeString;
}

function App() {
  const s = useCurrentTime();
  console.log(s);

  return <div className="App">{s}</div>;
}

ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.development.js"></script>

演示:https://codesandbox.io/s/gallant-bas-3lq5w?file=/src/App.js (使用 StrictMode )
这是一个使用生产库的片段;它仍然记录两次:

const { useState, useEffect } = React;

function useCurrentTime() {
  const [timeString, setTimeString] = useState("");

  useEffect(() => {
    const intervalID = setInterval(() => {
      setTimeString(new Date().toLocaleTimeString());
    }, 100);
    return () => clearInterval(intervalID);
  }, []);

  return timeString;
}

function App() {
  const s = useCurrentTime();
  console.log(s);

  return <div className="App">{s}</div>;
}

ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

但是,当我打开 Developer's Console 时,我看到每次只打印一次,并且在 codeandbox.io 的控制台中,我看到它打印了一次。
然后,如果我使用 create-react-app 创建一个独立的 React 应用程序,并使用上面的代码,每次都会打印两次。
如何理解这种行为,根据不同情况打印一次或两次?我的想法是,如果状态发生变化,那么 App使用新字符串 重新渲染一次 ,所以打印一次。奇怪的是为什么它打印了两次,但是当开发控制台打开时,它是一次?

最佳答案

据我所知,我们看到的双重电话 App是预期的行为。来自 useState documentation :

Bailing out of a state update

If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. (React uses the Object.is comparison algorithm.)

Note that React may still need to render that specific component again before bailing out. That shouldn’t be a concern because React won’t unnecessarily go “deeper” into the tree. If you’re doing expensive calculations while rendering, you can optimize them with useMemo.


其中的关键部分是“请注意,React 可能仍需要在退出之前再次渲染该特定组件……”和“……React 不会不必要地“深入”到树中……”
实际上,如果我更新您的示例以使其使用子组件来显示时间字符串,我们只会看到该子组件被调用 一次根据 timeString值而不是 App 的两倍是,即使子组件未包含在 React.memo 中:

const { useState, useEffect } = React;

function useCurrentTime() {
    const [timeString, setTimeString] = useState("");
  
    useEffect(() => {
        const intervalID = setInterval(() => {
            setTimeString(new Date().toLocaleTimeString());
        }, 100);
        return () => clearInterval(intervalID);
    }, []);
  
    return timeString;
}

function ShowTime({timeString}) {
    console.log("ShowTime", timeString);
    return <div className="App">{timeString}</div>;
}

function App() {
    const s = useCurrentTime();
    console.log("App", s);
  
    return <ShowTime timeString={s} />;
}

ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

当我运行它时,我看到:
App 09:57:14
ShowTime 09:57:14
App 09:57:14
App 09:57:15
ShowTime 09:57:15
App 09:57:15
App 09:57:16
ShowTime 09:57:16
App 09:57:16
App 09:57:17
ShowTime 09:57:17
App 09:57:17
App 09:57:18
ShowTime 09:57:18
App 09:57:18
App 09:57:19
ShowTime 09:57:19
App 09:57:19
App 09:57:20
ShowTime 09:57:20
App 09:57:20
请注意,尽管 ApptimeString 的每个值调用两次, ShowTime只调用一次。
我应该注意到这比 class 更自动。成分。相当于class如果您没有实现 shouldComponentUpdate ,组件将每秒更新 10 次. :-)
您在 CodeSandbox 上看到的一些内容很可能是由于 StrictMode , 更多关于 here .但是两次调用 App对于每个 timeString值(value)只是 React 做它的事情。

关于javascript - 为什么使用 Hooks 的 ReactJS 组件会根据开发者控制台是否打开而呈现一次或两次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66525901/

相关文章:

reactjs - 当我尝试在 useEffect 中 setState 时它不起作用

javascript - 如何从 HTML 中提取 JSON 序列化? C#

JavaScript "getelementsby"css 问题

Python - 从 ReactJS div 中抓取列表内容

reactjs - 使用浏览器历史记录 admin-on-rest

javascript - 我应该使用 connect 还是 hooks 来进行 React Redux,哪个性能更好?

javascript - 如何使用 onChange 事件对多个输入的值进行求和、除法 | ReactJS

javascript - 结束流错误后写入

javascript - 我正在尝试使用 jQuery 创建 "Sinking ships"

reactjs - 跨组件的 useMemo 行为