首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么使用钩子呈现一次或两次的ReactJS组件(取决于开发人员控制台是否打开)?

为什么使用钩子呈现一次或两次的ReactJS组件(取决于开发人员控制台是否打开)?
EN

Stack Overflow用户
提问于 2021-03-08 07:40:28
回答 1查看 135关注 0票数 6

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

代码语言:javascript
复制
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"));
代码语言:javascript
复制
<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)

下面是一个使用生产库的代码片段;它仍然记录两次:

代码语言:javascript
复制
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"));
代码语言:javascript
复制
<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>

但是,当我打开开发人员的控制台时,每次只打印一次,而且在codesandbox.io的控制台中,我看到它打印了一次。

然后如果我用创建一个独立的React,并使用上面的代码,每次打印两次。

如何理解这种行为,根据不同的情况打印一次或两次?我的想法是,如果状态改变了,那么App就会被重新呈现,使用新的字符串 once ,所以它被打印了一次。奇怪的是,为什么它要打印两次,但是当Dev控制台打开时,它就只打印了一次?

EN

回答 1

Stack Overflow用户

发布于 2021-03-08 10:01:52

据我所知,我们看到的对App的双重调用是预期的行为。来自useState documentation

退出状态更新

如果您将状态挂钩更新为与当前状态相同的值,则React将在不呈现子状态或触发效果的情况下退出。(React使用Object.is比较算法。)

注意,在退出之前,React可能仍然需要再次呈现特定的组件。这不应该是一个问题,因为反应不会不必要地“深入”到树上。如果您在渲染时进行昂贵的计算,则可以使用useMemo优化它们。

其中的关键部分是“在退出之前,可能仍然需要重新呈现特定的组件.”而且"...React不会不必要地“深入到树上.”

实际上,如果我更新您的示例,以便它使用一个子组件来显示时间字符串,那么我们只看到该子组件在每个值中调用一次,而不是App值的两倍,即使子组件没有包装在React.memo中。

代码语言:javascript
复制
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"));
代码语言:javascript
复制
<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>

当我运行它时,我看到:

代码语言:javascript
复制
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调用只是在做它的事情。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66525901

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档