Как использовать componentWillMount() в React Hooks?

В официальных документах React упоминается -

Если вы знакомы с методами жизненного цикла класса React, вы можете использовать useEffect Hook как комбинацию componentDidMount, componentDidUpdate и componentWillUnmount.

У меня вопрос - как мы можем использовать метод lifeWlementWillMount componentWillMount() ловушке?

Ответы

Ответ 1

Вы не можете использовать любые из существующих методов жизненного цикла (componentDidMount, componentDidUpdate, componentWillUnmount и т.д.) В ловушке. Они могут использоваться только в компонентах класса. А крючки вы можете использовать только в функциональных компонентах. Что ниже строка из документа React

Если вы знакомы с методами жизненного цикла класса React, вы можете использовать useEffect Hook как componentDidMount, componentDidUpdate и componentWillUnmount вместе.

Предположим, вы можете имитировать эти методы жизненного цикла из компонента класса в функциональные компоненты.

Код внутри componentDidMount запускается один раз, когда компонент монтируется. Эквивалент крючка useEffect для этого поведения

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

Обратите внимание на второй параметр здесь (пустой массив). Это будет работать только один раз.

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

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

componentWillUnmount используется для очистки (например, удаление списков событий, отмена таймера и т.д.). Скажем, вы добавляете список событий в componentDidMount и удаляете его в componentWillUnmount, как показано ниже.

componentDidMount() {
  window.addEventListener('mousemove', () => {})
}

componentWillUnmount() {
  window.removeEventListener('mousemove', () => {})
}

Хук-эквивалент вышеприведенного кода будет следующим

useEffect(() => {
  window.addEventListener('mousemove', () => {});

  // returned function will be called on component unmount 
  return () => {
    window.removeEventListener('mousemove', () => {})
  }
}, [])

Ответ 2

По данным responsejs.org, компонентWillMount не будет поддерживаться в будущем. https://reactjs.org/docs/react-component.html#unsafe_componentwillmount

Нет необходимости использовать componentWillMount.

Если вы хотите что-то сделать до монтирования компонента, просто сделайте это в конструкторе().

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

Сетевые запросы могут быть выполнены в componentDidMount.

Надеюсь, это поможет.


обновлено 08/03/2019

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

Просто сделайте это в useState.

const helloWorld=()=>{
    const [value,setValue]=useState(0) //initialize your state here
    return <p>{value}</p>
}
export default helloWorld;

или, может быть, вы хотите запустить функцию в componentWillMount, например, если ваш оригинальный код выглядит следующим образом:

componentWillMount(){
  console.log('componentWillMount')
}

с помощью hook, все, что вам нужно сделать, это удалить метод жизненного цикла:

const hookComponent=()=>{
    console.log('componentWillMount')
    return <p>you have transfered componeWillMount from class component into hook </p>
}

Я просто хочу добавить кое-что к первому ответу об useEffect.

useEffect(()=>{})

useEffect запускается при каждом рендеринге, это комбинация componentDidUpdate, componentDidMount и ComponentWillUnmount.

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

Если мы добавим пустой массив в useEffect, он будет запущен сразу после монтирования компонента. Это потому, что useEffect будет сравнивать массив, который вы передали ему. Таким образом, это не должен быть пустой массив. Это может быть массив, который не изменяется. Например, это может быть [1,2,3] или ['1,2']. useEffect по-прежнему работает только при подключенном компоненте.

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

Я создал образец для крючка. Пожалуйста, проверьте это.

https://codesandbox.io/s/kw6xj153wr


Обновлено 21/08/2019

Это был белый, так как я написал ответ выше. Есть кое-что, на что, я думаю, нужно обратить внимание. Когда вы используете

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

Когда реакция сравнивает значения, переданные вами в массив [], он использует Object.is() для сравнения. Если вы передаете ему объект, например

useEffect(()=>{},[{name:'Tom'}])

Это точно так же, как:

useEffect(()=>{})

Он будет перерисовываться каждый раз, потому что когда Object.is() сравнивает объект, он сравнивает его ссылку, а не само значение. Это то же самое, что и то, почему {} === {} возвращает false, потому что их ссылки разные. Если вы все еще хотите сравнить сам объект, а не ссылку, вы можете сделать что-то вроде этого:

useEffect(()=>{},[JSON.stringify({name:'Tom'})])

Ответ 3

хук useComponentDidMount

В большинстве случаев useComponentDidMount является инструментом для использования. Он будет запущен только один раз, после монтирования компонента (начальная визуализация).

 const useComponentDidMount = func => useEffect(func, []);

useComponentWillMount

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

const useComponentWillMount = func => {
  const willMount = useRef(true);

  if (willMount.current) {
    func();
  }

  useComponentDidMount(() => {
    willMount.current = false;
  });
};

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

Демо

const Component = (props) => {
  useComponentWillMount(() => console.log("Runs only once before component mounts"));
  useComponentDidMount(() => console.log("Runs only once after component mounts"));
  ...

  return (
    <div>{...}</div>
  );
}

Полная демонстрация

Ответ 4

useLayoutEffect может выполнить это с помощью пустого набора наблюдателей ([]), если функциональность фактически похожа на componentWillMount - он будет работать до того, как первый контент попадет в DOM - хотя на самом деле есть два обновления, но они синхронизируются перед обращением к экран.

например:


function MyComponent({ ...andItsProps }) {
     useLayoutEffect(()=> {
          console.log('I am about to render!');
     },[]);

     return (<div>some content</div>);
}

Преимущество по useState с useState с инициализатором/установщиком или useEffect заключается в том, что, хотя он может вычислять useEffect рендеринга, нет фактических повторных рендерингов в DOM, которые пользователь заметит, и он запускается до первого заметного рендера, который не является кейс для useEffect. Недостатком является, конечно, небольшая задержка вашего первого рендера, так как проверка/обновление должны выполняться перед рисованием на экране. Это действительно зависит от вашего варианта использования, хотя.

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

Ответ 5

Я написал пользовательский хук, который будет запускать функцию один раз перед первым рендерингом.

useBeforeFirstRender.js

import { useState, useEffect } from 'react'

export default (fun) => {
  const [hasRendered, setHasRendered] = useState(false)

  useEffect(() => setHasRendered(true), [hasRendered])

  if (!hasRendered) {
    fun()
  }
}

Использование:

import React, { useEffect } from 'react'
import useBeforeFirstRender from '../hooks/useBeforeFirstRender'


export default () => { 
  useBeforeFirstRender(() => {
    console.log('Do stuff here')
  })

  return (
    <div>
      My component
    </div>
  )
}

Ответ 6

https://reactjs.org/docs/hooks-reference.html#usememo

Помните, что функция, переданная useMemo, запускается во время рендеринга. Не делайте там ничего, что вы обычно не делаете во время рендеринга. Например, побочные эффекты принадлежат useEffect, а не useMemo.