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

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


person jeyko    schedule 27.12.2018    source источник


Ответы (8)


Для стабильной версии хуков (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]);

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

person Mertcan Diken    schedule 12.02.2019
comment
Подробное объяснение! Есть ли способ имитировать componentDidReceiveProps? - person jeyko; 13.02.2019
comment
Я не знаю об этом, даже если он существует. Вы можете проверить это в этой теме, github.com/facebook/react/issues/3279 - person Mertcan Diken; 13.02.2019
comment
Спасибо за это, так как я не знал о втором аргументе в useState. Всем, кто читает это, имейте в виду, что оставление второго аргумента undefined вызовет срабатывание вашего эффекта при каждом рендеринге (если я не ошибаюсь). - person dimiguel; 13.03.2019
comment
Вы имеете в виду зависимости useEffect (передача массива зависимостей)? Если да, то, если вы оставите его пустым, это ошибка в коде. Для деконструкции массива вам понадобятся оба параметра [count, setCount], потому что count - это ваша переменная состояния в этом примере, а setCount - ваша функция для обновления этого состояния. - person Mertcan Diken; 13.03.2019
comment
Спасибо за ответ. Документация по этому поводу находится здесь responsejs.org/docs/hooks-effect.html. - person Josh; 19.01.2020
comment
Я пытался использовать пустой массив зависимостей для имитации componentDidMount. Проблема в том, что это обычно приводит к предупреждению: React Hook useEffect имеет недостающую зависимость: ‹some prop›. Либо включите его, либо удалите массив зависимостей react-hooks / excustive-deps. После применения любого из предложенных исправлений он больше не ведет себя как componentDidMount. Я делаю что-то неправильно? - person Jonas Rosenqvist; 06.08.2020
comment
Этот ответ неверен, поскольку предполагает, что он является эквивалентом componentDidMount (вопрос был задан для эквивалента), он показывает только обходной путь, который работает в некоторых случаях. В правильном ответе должно быть указано, что эквивалента нет, и показаны рекомендуемые обходные пути для всех случаев использования. - person kca; 20.12.2020
comment
Ответ не утверждает, что он равен чему-либо; предложение заканчивается надеждой, что оно поможет. Так что я не вижу здесь ничего плохого. И, похоже, многим это помогло. Но я открыт для любых предложений по повышению надежности этого ответа, поскольку в этом вся цель. @kca - person Mertcan Diken; 21.12.2020
comment
Это самая краткая документация по useEffect () в Интернете. - person nonethewiser; 09.04.2021

Не существует точного эквивалента для componentDidMount в перехватчиках реакции.


По моему опыту, перехватчики реакции требуют другого мышления при их разработке, и, вообще говоря, вы не должны сравнивать их с методами класса, такими как componentDidMount.

С учетом сказанного, есть способы, которыми вы можете использовать хуки для получения эффекта, аналогичного componentDidMount.

Решение 1.

useEffect(() => {
  console.log("I have been mounted")
}, [])

Решение 2:

const num = 5

useEffect(() => {
  console.log("I will only run if my deps change: ", num)
}, [num])

Решение 3 (с функцией):

useEffect(() => {
  const someFunc = () => {
    console.log("Function being run after/on mount")
  }
  someFunc()
}, [])

Решение 4 (useCallback):

const msg = "some message"

const myFunc = useCallback(() => {
  console.log(msg)
}, [msg])

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

Решение 5 (проявите творческий подход):

export default function useDidMountHook(callback) {
  const didMount = useRef(null)

  useEffect(() => {
    if (callback && !didMount.current) {
      didMount.current = true
      callback()
    }
  })
}

Стоит отметить, что решение 5 следует использовать только в том случае, если ни одно из других решений не подходит для вашего варианта использования. Если вы все же решите, что вам нужно решение 5, я рекомендую использовать этот готовый крючок use-did- смонтировать.

Источник (с более подробной информацией): Использование componentDidMount в перехватчиках реакции

person Atomicts    schedule 26.11.2020

Функциональных компонентов componentDidMount нет, но перехватчики React предоставляют способ эмуляции поведения с помощью перехватчика 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/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

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

person Yangshun Tay    schedule 29.12.2018

Хотя принятый ответ работает, это не рекомендуется. Если у вас более одного состояния и вы используете его с 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 в это время, но по мере роста вашего приложения есть вероятность, что вы МОЖЕТЕ столкнуться с некоторыми проблемами. Так что вместо того, чтобы переписывать на этом этапе, лучше сделать это на ранней стадии.

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

person Aniket Kariya    schedule 03.09.2020
comment
Я сделал это. У меня возникла проблема с использованием крючков. Проблема исчезла после преобразования его в класс. - person Julez; 21.09.2020
comment
Мне еще предстоит увидеть ошибку useEffect, которую нельзя было бы решить путем рефакторинга кода - включая этот пример. Использование версии обратного вызова setState или полное перемещение вызывающей нарушение функции из цикла рендеринга часто дает трюк - в противном случае ваше состояние, вероятно, слишком сложное и вам нужно реализовать свой собственный редуктор. Хуки не являются обязательными, но это явно будущее React. Я рекомендую прочитать эту отличную статью об useEffect - она ​​действительно помогла мне обойдите его, когда я начал сталкиваться с этими проблемами. - person lawrence-witt; 20.02.2021

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

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

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

person Aravinth    schedule 15.10.2020

Хук useEffect () позволяет нам реализовать функциональные возможности componentDidMount, componentDidUpdate componentWillUnMount.

Различный синтаксис useEffect () позволяет реализовать каждый из вышеперечисленных методов.

i) componentDidMount

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

ii) componentDidUpdate

useEffect(() => {
  //code here
}, [x,y,z]);

//where x,y,z are state variables on whose update, this method should get triggered

iii) componentDidUnmount

useEffect(() => {
  //code here
  return function() {
    //code to be run during unmount phase
  }
}, []);

Вы можете проверить официальный сайт реакции для получения дополнительной информации. Официальная страница React на хуках

person Vanmee    schedule 05.02.2021

Информация об асинхронных функциях внутри хука:

Обратные вызовы эффектов синхронны, чтобы предотвратить состояние гонки. Поместите асинхронную функцию внутрь:

useEffect(() => {
  async function fetchData() {
    // You can await here
    const response = await MyAPI.getData(someId);
    // ...
  }
  fetchData();
}, [someId]); // Or [] if effect doesn't need props or state
person zemil    schedule 19.03.2021

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

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

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

person markmoxx    schedule 27.12.2018
comment
Это решение не идеально. Плохая идея использовать значение состояния только для определения того, смонтирован ли компонент. Кроме того, если бы вы использовали свойство, было бы лучше использовать ref, поскольку он не запускал бы повторную визуализацию. - person Yangshun Tay; 30.12.2018