componentDidMount для функции React / компонента хуков?

99

Есть ли способы моделирования componentDidMountфункциональных компонентов React с помощью хуков?

Джейко
источник

Ответы:

199

Для стабильной версии хуков (React Version 16.8.0+)

За componentDidMount

useEffect(() => {
  // Your code here
}, []);

За componentDidUpdate

useEffect(() => {
  // Your code here
}, [yourDependency]);

За componentWillUnmount

useEffect(() => {
  // componentWillUnmount
  return () => {
     // Your code here
  }
}, [yourDependency]);

Итак, в этой ситуации вам нужно передать свою зависимость в этот массив. Предположим, у вас есть такое состояние

const [count, setCount] = useState(0);

И всякий раз, когда количество увеличивается, вы хотите повторно визуализировать свой функциональный компонент. Тогда вы useEffectдолжны выглядеть так

useEffect(() => {
  // <div>{count}</div>
}, [count]);

Таким образом, всякий раз, когда ваш счетчик обновляется, ваш компонент будет повторно визуализироваться. Надеюсь, это немного поможет.

Мерткан Дикен
источник
Подробное объяснение! Есть ли способ имитировать componentDidReceiveProps?
jeyko
1
Я не знаю об этом, даже если он существует. Вы можете проверить это в этой ветке github.com/facebook/react/issues/3279
Mertcan Diken
1
Спасибо за это, так как я не знал о втором аргументе в useState. Всем, кто читает это, имейте в виду, что оставление второго аргумента undefinedприведет к срабатыванию вашего эффекта при каждом рендере (если я не ошибаюсь).
dimiguel
Вы имеете в виду зависимости useEffect (передача массива зависимостей)? Если да, то, если вы оставите его пустым, это ошибка в коде. Для деконструкции массива вам понадобятся оба параметра [count, setCount], потому что count - это ваша переменная состояния в этом примере, а setCount - ваша функция для обновления этого состояния.
Mertcan Diken
Спасибо за ответ. Документация по этому поводу находится здесь responsejs.org/docs/hooks-effect.html
Джош
3

Хотя принятый ответ работает, это не рекомендуется. Если у вас более одного состояния и вы используете его с useEffect, он выдаст предупреждение о добавлении его в массив зависимостей или о том, что он не используется вообще.

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

Взять, к примеру

function App() {
  const [appointments, setAppointments] = useState([]);
  const [aptId, setAptId] = useState(1);

  useEffect(() => {
    fetch('./data.json')
      .then(response => response.json())
      .then(result => {
        const apts = result.map(item => {
          item.aptId = aptId;
          console.log(aptId);
          setAptId(aptId + 1);
          return item;
        })
        setAppointments(apts);
      });
  }, []);

  return(...);
}

а также

class App extends Component {
  constructor() {
    super();
    this.state = {
      appointments: [],
      aptId: 1,
    }
  }

  componentDidMount() {
    fetch('./data.json')
      .then(response => response.json())
      .then(result => {
        const apts = result.map(item => {
          item.aptId = this.state.aptId;
          this.setState({aptId: this.state.aptId + 1});
          console.log(this.state.aptId);
          return item;
        });
        this.setState({appointments: apts});
      });
  }

  render(...);
}

Это только для примера . так что давайте не будем говорить о лучших практиках или потенциальных проблемах с кодом. Оба варианта имеют одинаковую логику, но последний работает только так, как ожидалось. Вы можете получить функциональность componentDidMount с запущенным useEffect в это время, но по мере роста вашего приложения есть вероятность, что вы МОЖЕТЕ столкнуться с некоторыми проблемами. Поэтому, чем переписывать на этом этапе, лучше сделать это на ранней стадии.

Кроме того, ООП не так уж и плох, если бы было достаточно процедурно-ориентированного программирования, у нас никогда бы не было объектно-ориентированного программирования. Иногда это больно, но лучше (технически не говоря уже о личных проблемах).

Аникет Кария
источник
1
Я сделал это. У меня возникла проблема с использованием крючков. Проблема исчезла после преобразования его в класс.
Julez
2

Там нет componentDidMountна функциональных компонентах, но Реагировать Крючки обеспечивают способ , которым Вы можете эмулировать поведение с помощью useEffectкрючка.

Передайте пустой массив в качестве второго аргумента, useEffect()чтобы запускать только обратный вызов только при монтировании.

Пожалуйста, прочтите документацию поuseEffect .

function ComponentDidMount() {
  const [count, setCount] = React.useState(0);
  React.useEffect(() => {
    console.log('componentDidMount');
  }, []);

  return (
    <div>
      <p>componentDidMount: {count} times</p>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click Me
      </button>
    </div>
  );
}

ReactDOM.render(
  <div>
    <ComponentDidMount />
  </div>,
  document.querySelector("#app")
);
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>

Яншун Тай
источник
0

Вы хотите использовать useEffect(), который, в зависимости от того, как вы используете функцию, может действовать так же, как componentDidMount ().

Например. вы можете использовать настраиваемое loadedсвойство состояния, для которого изначально установлено значение false, и переключить его на true при рендеринге и активировать эффект только при изменении этого значения.

Документация

markmoxx
источник
1
Это решение не идеально. Плохая идея использовать значение состояния только для определения того, смонтирован ли компонент. Кроме того, если бы вы использовали свойство, было бы лучше использовать ref, поскольку он не запускал бы другой повторный рендеринг.
Яншун Тай
0

точный эквивалентный крючок для componentDidMount () -

useEffect(()=>{},[]);

надеюсь, что это поможет :)

Аравинт
источник