Почему код (функциональный) для хука продолжает отображаться? (по сравнению с классом)

#javascript #reactjs #react-hooks #react-state #react-lifecycle

#javascript #reactjs #реагирующие перехваты #реагировать-состояние #реагировать-жизненный цикл

Вопрос:

Я только начал реагировать…

Этот код просто отображается через 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;

 

Ответ №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:

Поскольку вы инициализируете загрузку с истинным значением в состоянии. и всякий раз, когда состояние изменяется, функциональные компоненты перезаписываются, и это не происходит в компоненте на основе класса, поскольку вы использовали метод жизненного цикла компонента. Вы должны использовать «useEffect» в функциональном компоненте.

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

вы можете прочитать об этом здесь https://reactjs.org/docs/hooks-effect.html

Ответ №3:

Ответ от MubtadaNaqvi, к сожалению, приведет к бесконечному циклу. Вы должны правильно применить useEffect:

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

Комментарии:

1. Это тоже не сработает, поскольку установщик не принимает функцию в качестве аргумента.

2. Вы можете указать prevState в setState, и это то, что я сделал. setIsLoading(false) был бы еще один вариант.

3. Понятно, я думал, что это работает только для компонентов на основе классов.

4. Поступая таким образом, вы избежали бы useEffect linting жалобы на то, что у него отсутствует зависимость, загружается

5. Достаточно справедливо. Хотя в этом случае простая установка его false может иметь больше смысла