【问题标题】:Why does the code(funtional) for the hook keep rendering? (compared to Class)为什么钩子的代码(功能)不断渲染? (与类相比)
【发布时间】:2021-02-19 10:04:48
【问题描述】:

我刚开始反应……

此代码仅在 3 秒后使用布尔值呈现。

但是下面的代码几乎每三秒就会不断渲染……渲染……渲染……

import React, { useState } from "react";

const App = () => {
  const [isLoading, setIsLoading] = useState(true);

  setTimeout(() => {
    setIsLoading(!isLoading);
  }, 3000);

  return <h1>{isLoading ? "Loading" : "we are ready"}</h1>;
};

export default App;


但是这段代码运行良好。是什么原因?

import React, { Component } from "react";

class App extends React.Component {
  state = {
    isLoading: true,
  };

  componentDidMount() {
    setTimeout(() => {
      this.setState({
        isLoading: false,
      });
    }, 3000);
  }

  render() {
    return <div>{this.state.isLoading ? "Loading..." : "we are ready"}</div>;
  }
}

export default App;

【问题讨论】:

    标签: javascript reactjs react-hooks react-state react-lifecycle


    【解决方案1】:

    每次渲染都会调用一个函数组件。这意味着在状态更改后的每次重新渲染时也会创建超时,就像在您的第一个示例中那样实施时。要使用组件生命周期,您应该使用 useEffect 挂钩:https://reactjs.org/docs/hooks-reference.html#useeffect

    import React, { useEffect, useState } from "react";
    
    const App = () => {
      const [isLoading, setIsLoading] = useState(true);
    
      // Set a timeout ONCE when the component is rendered for the first time
      // The second argument [] signifies that nothing will trigger the effect during re-renders
      useEffect(() => {
        setTimeout(() => {
          setIsLoading(false);
        }, 3000);
      }, [])
    
      return <h1>{isLoading ? "Loading" : "we are ready"}</h1>;
    };
    
    export default App;
    

    【讨论】:

      【解决方案2】:

      因为您正在使用状态中的 true 值初始化 isLoading。并且每当状态更改时,功能组件都会重新呈现,并且它不会发生在基于类的组件中,因为您使用了组件生命周期方法。您应该在功能组件中使用“useEffect”。

        useEffect(() => {
          setTimeout(() => {
            setIsLoading(!isLoading);
          }, 3000);
        });
      

      你可以在这里阅读https://reactjs.org/docs/hooks-effect.html

      【讨论】:

        【解决方案3】:

        不幸的是,MubtadaNaqvi 的回答将导致无限循环。您应该正确应用 useEffect:

          useEffect(() => {
            setTimeout(() => {
              setIsLoading(isLoading => !isLoading);
            }, 1000);
          }, [])
        

        【讨论】:

        • 这也不起作用,因为 setter 不将函数作为参数。
        • 您可以在 setState 中提供一个 prevState,这就是我所做的。 setIsLoading(false) 是另一种选择。
        • 我明白了,我认为这只适用于基于类的组件。
        • 这样做可以避免 useEffect linting 抱怨它缺少依赖 isLoading
        • 很公平。不过,在这种情况下,只需将其设置为 false 可能更有意义
        猜你喜欢
        • 1970-01-01
        • 2020-07-09
        • 2020-01-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-23
        • 2014-12-17
        相关资源
        最近更新 更多