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

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

If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.

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

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
350
0
317 365
20
Перейти к ответу Данный вопрос помечен как решенный

Ответы 20

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

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

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

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

Сетевые запросы можно выполнять в componentDidMount.

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


обновлено 03.08.2019

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

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

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

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

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

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

const hookComponent=()=>{
    console.info('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(()=>{},[])

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

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

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

useEffect(()=>{})

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

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

Обновление от 07.09.2021:

Несколько обновлений о зависимости:

Вообще говоря, если вы используете функцию или объект в качестве зависимости, они всегда будут повторно отрисовываться. Но в React уже есть решение: useCallback и useMemo.

useCallback может запоминать функцию. useMemo может запоминать объект.

См. Эту статью:

https://javascript.plainenglish.io/5-useeffect-infinite-loop-patterns-2dc9d45a253f

и вопрос был в том, как это реализовать с помощью хуков

Shubham Khatri 26.11.2018 14:27

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

MING WU 27.11.2018 04:01

Теперь, когда вы упомянули, что componentDidMount - это правильный жизненный цикл для использования, вы могли бы добавить, как реализовать это в своем ответе, и тогда ваш ответ будет иметь больше смысла, чем принятый ответ

Shubham Khatri 27.11.2018 06:19

это верно. Спасибо, что указали на это. Я добавлю это позже на этой неделе.

MING WU 27.11.2018 08:37

Конечно, это должен быть принятый ответ - он объясняет, что ComponentWillMount недоступен в парадигме хуков. Инициализация в функциональных компонентах упрощена - она ​​просто должна быть частью функции.

Shiraz 15.05.2019 14:58

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

Overcode 26.01.2020 21:32
Ответ принят как подходящий

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

If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.

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

Код внутри 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', () => {})
  }
}, [])

Хорошее объяснение для других событий жизненного цикла, но это не вопрос конкретно об альтернативе componentWillMount ().

Shiraz 15.05.2019 14:56

В примерах PanResponder я видел, что требуется componentWillMount, иначе вы получите undefined panHandlers.

Dror Bar 15.07.2019 11:52

Обратите внимание на [] как на второй аргумент useEffect. Без него эффект будет запускаться при каждом рендере, а не только при первом рендеринге. Поскольку [] каждый раз одно и то же, React считает, что эффект уже применен (читай: динамическое программирование / запоминание при воспроизведении), и не запускает повторно вашу функцию.

Nate Symer 28.08.2019 19:15

А что, если нам не нужен componentDidMount и просто нужно использовать альтернативу componentWillUnmount в функциональном компоненте?

jake-ferguson 29.08.2019 10:31

Теперь я действительно понимаю функцию useEffect(), спасибо.

Iharob Al Asimi 03.09.2019 21:07

Спасибо, это помогло мне очистить компонент слайдера изображений, который использовал setInterval для изменения слайдов. Требовалось очистить интервал при демонтаже компонента.

StefanBob 30.09.2019 21:42

Почему это принятый ответ ?? Вы не упомянули эквивалент ловушки для componentWillMount

Mykybo 04.11.2019 13:51

Те, кто говорит, что он не упомянул эквивалент «componentWillUnmount», не обращают внимания, в частности, на оператор «return» в хуке useEffect, где вы можете выполнять все задачи, связанные с «размонтированием».

techexpert 23.02.2020 23:52

@techexpert Вопрос задан для эквивалента componentWillMount, а не componentWillUnmount. Этот ответ действительно вообще не отвечает на вопрос, а просто повторяет то, что OP уже подразумевал знать.

JoshuaCWebDeveloper 24.02.2020 06:42

Если я использую последний вариант, пустой массив, что мне делать, если я хочу прочитать состояние, но он продолжает жаловаться, что я должен добавить его в массив зависимостей? Я хочу запускать код только тогда, когда компонент размонтируется.

sepha 26.02.2020 10:06

@JoshuaCWebDeveloper .. Понятно, моя ошибка. Но в любом случае componentWillMount был объявлен устаревшим еще в 2018 году. Вы можете выполнять практически любую инициализацию и другие вычисления в функциональном компоненте перед оператором return (). То же самое, что и в конструкторе класса. Делает componentWillMount несколько избыточным, имо

techexpert 04.03.2020 02:10

@techexpert На самом деле, любой код в функциональном компоненте перед оператором return фактически будет выполнен каждый, когда компонент будет визуализирован, нет будет использоваться только в первый раз, как конструктор (или ранее componentWillMount). Ответ @Ben Carp - это ответ с наибольшим количеством голосов, который фактически отвечает на вопрос.

JoshuaCWebDeveloper 08.03.2020 03:37

этот ответ НАМНОГО лучше, чем многие другие глупые статьи. Большое спасибо за краткий ответ.

Bryan Jyh Herng Chong 25.03.2020 03:55

Я думаю, что обработчик событий для 'mousmove', определенный в частях remove и addEvent, отличается из-за того, что () => {} создает две разные ссылки на функции. Следовательно, это может вызвать ошибку.

Biboswan 15.04.2020 12:03

когда-то нам нужно установить состояние в componentWillMount, без этого рендеринг компонента будет стоить дважды, особенно если вы запускаете многоуровневый компонент, u будет рендерить дважды для всех компонентов, если вы не можете использовать componentWillMount на верхнем слое (предположим, что вы необходимость)

user192344 29.04.2020 14:19

хорошее объяснение, но это не отвечает на вопрос

Luk Aron 22.12.2020 03:57

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

mbd 02.07.2021 00:46

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

Remember that the function passed to useMemo runs during rendering. Don’t do anything there that you wouldn’t normally do while rendering. For example, side effects belong in useEffect, not useMemo.

usememo предназначен для оптимизации производительности. Хук будет отрисован снова после того, как он уже смонтирован, если изменится свойство, что противоречит цели автора.

max54 23.05.2019 17:26

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

Shah 26.08.2021 21:39

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

Например:


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

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

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

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

useLayoutEffect - отличный способ !!!! Это ответ на мой вопрос относительно проверки того, вошел ли пользователь в систему. (Проблема заключалась в том, что компоненты загружались, а затем проверяли, вошел ли пользователь в систему.) Мой вопрос, однако, является ли это стандартной практикой? Я не вижу слишком много мест

Jessica 16.05.2019 21:11

да, это довольно часто; также упоминается в официальных документах React - только более мелким текстом из-за разветвлений двойного рендеринга DOM для запуска логики до того, как пользователь заметит.

rob2d 17.06.2019 18:04

Фактически он запускается после рендеринга компонента. Так что он полностью отличается от componentWillMount.

Jiri Mihal 26.03.2020 13:08

useComponentWillMount хук

const useComponentWillMount = (cb) => {
    const willMount = useRef(true)

    if (willMount.current) cb()

    willMount.current = false
}

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

useComponentDidMount хук

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

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

парадигма useEffect

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

function Post({postID}){
  const [post, setPost] = useState({})

  useEffect(()=>{
    fetchPosts(postID).then(
      (postObject) => setPost(postObject)
    )
  }, [postID])

  ...
}

В приведенном выше примере эффект касается получения содержимого сообщения. Вместо определенного момента времени он имеет значение, от которого зависит - postID. Каждый раз, когда postID получает новое значение (включая инициализацию), он запускается повторно.

Компонент будет смонтировать обсуждение

В компонентах класса componentWillMount считается устаревшим (источник 1, источник2). Это устаревший вариант, поскольку он может запускаться более одного раза, и есть альтернатива - использовать конструктор. Эти соображения не имеют отношения к функциональному компоненту.

Это единственный ответ, который отвечает на вопрос и имеет смысл. Спасибо!

chumakoff 25.07.2019 15:16

Единственная проблема в том, что вы получаете дополнительный рендер из-за задействованного обновления состояния. Используя вместо этого ссылку, вы получите желаемое поведение без дополнительной визуализации: `const useComponentWillMount = func => {const willMount = useRef (true); useEffect (() => {willMount.current = false;}, []); если (willMount.current) {func (); }}; `

remix23 15.08.2019 15:26

Эта функциональная реализация componentWillMount на основе useEffect имеет две проблемы. Во-первых, в функциональных компонентах нет жизненного цикла монтирования, оба перехватчика будут запускаться после рендеринга компонента, поэтому Runs only once before component mounts вводит в заблуждение. Во-вторых, componentWillMount вызывается при рендеринге сервера, а useEffect - нет. Многие библиотеки по-прежнему полагаются на UNSAFE_componentWillMount, потому что в настоящее время это единственный способ вызвать побочный эффект на стороне сервера.

Paolo Moretti 05.09.2019 12:28

@PaoloMoretti, спасибо. Этот хук componentWillMount не является точным эквивалентом жизненного цикла componentWillMount в компоненте класса. Однако переданная ему функция будет запущена немедленно, только при первом вызове. Практически это означает, что он будет запущен до того, как он будет отрисован, и даже до того, как он вернет значение в первый раз. Можем ли мы договориться об этом? Я согласен с тем, что использование имени componentWillMount не идеально, поскольку это имя несет определенный смысл из версии жизненного цикла класса. Возможно, мне лучше назвать это «useRunPreMount».

Ben Carp 05.09.2019 12:49

Мне жаль, что я на самом деле не осознавал, что обратный вызов useComponentWillMount запускается при первом вызове. В таком случае то, что я сказал о первой проблеме, неверно, я думаю, что это, возможно, ближайшая реализация componentWillMount с хуками. Вторая проблема все еще актуальна, потому что useEffect не работает в SSR, поэтому я думаю, что он всегда будет выполнять обратный вызов, поскольку willMount.current не будет установлен на falseuseEffect.

Paolo Moretti 05.09.2019 15:13

@PaoloMoretti, я не совсем понимаю. Я не работаю с SSR, но я понимаю, что на SSR componentWillMount запускается дважды - один раз на сервере и один раз на клиенте. Я думаю, что то же самое верно и для обратного вызова, который передается в useComponentDidMount. useComponentDidMount передает useEffect, чтобы остановить вызов обратного вызова. Пока не будет выполнен обратный вызов useEffect, функция компонента будет выполняться дважды - один раз на сервере и один раз на клиенте. Разве это не так?

Ben Carp 05.09.2019 18:24

Спасибо за эти фрагменты! Они должны быть встроены в хуки для React. Семантическое преимущество наличия крючков, которые легко описывают то, что они делают, по-прежнему остается пустым после того, как компоненты класса IMO остались позади. Я думаю, что хуки и функциональные компоненты - это то, что нужно, но эквивалент компонентаDidMount в useEffect уродлив, и, если кто-то хорошо не знает React, будет сбивать с толку. Команда React должна была включить что-то подобное!

Matt Goodwin 12.11.2019 20:24

Согласен, что это единственно правильный ответ на вопрос. В моем варианте использования я хотел выполнить одноразовое действие перед отрисовкой. Использование useRef действительно выполнит это (как и пользовательский ref, представленный здесь). Спасибо!

JoshuaCWebDeveloper 24.02.2020 06:48

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

Jiri Mihal 26.03.2020 13:19

@JiriMihal см. Комментарий remix23 выше. Изначально я использовал useState, а remix23 предложил useRef. Я думаю, он прав. Я думаю, что useRef предназначен для dom-ссылок, но не только для этой цели.

Ben Carp 26.03.2020 17:48

@BenCarp Я вижу, в этом есть смысл. Заметил еще одну вещь. willMount.current = false; должен быть сразу после func();. Если func(); изменит состояние компонента, вы получите бесконечный цикл.

Jiri Mihal 26.03.2020 20:41

@JiriMihal, Хороший улов. Спасибо! Я исправил свой ответ. К счастью, такая ситуация заметна (если кто-то передает обратный вызов, который обновляет состояние, должен произойти бесконечный цикл и будет отображаться ошибка), и поэтому вряд ли он попадет в производство.

Ben Carp 09.04.2020 08:46

@BenCarp, большое спасибо за объяснение и демонстрацию. Я искал ответ на реализацию componentWillMount с использованием хуков, и ваша работа отлично. :)

Muntasir 22.07.2020 21:00

Что произойдет, если вы реализуете ловушку useComponentWillMount с useMemo вместо useEffect ??

norman123123 25.09.2020 23:54

@ norman123123, насколько я могу судить точно так же будет работать.

Ben Carp 26.09.2020 05:24

Ваш пример useRef великолепен, но в документации React специально сказано не использовать useMemo для этой цели. Вы можете полагаться на useMemo как на оптимизацию производительности, а не как на семантическую гарантию. responsejs.org/docs/hooks-reference.html#usememo

Naliba 25.05.2021 19:50

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

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.info('Do stuff here')
  })

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

Есть хороший обходной путь для реализации componentDidMount и componentWillUnmount с useEffect.

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

Следовательно, если мы используем ловушку useEffect вообще без зависимостей, ловушка будет вызываться только тогда, когда компонент смонтирован, а функция "очистки" вызывается, когда компонент размонтирован.

useEffect(() => {
    console.info('componentDidMount');

    return () => {
        console.info('componentWillUnmount');
    };
}, []);

Вызов функции возврата очистки вызывается только тогда, когда компонент отключен.

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

Как это поможет, если это не имеет отношения к componentWillMount? Я что-то упускаю?

ZenVentzi 13.11.2019 18:53

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

AfikDeri 18.11.2019 12:19

Это неправда, useEffect запускается только после рендеринга, а componentWillMount запускается до рендеринга компонента.

Overcode 26.01.2020 21:34

@Overcode Я говорил о componentDidMount, а не о componentWillMount. Я пропустил это в вопросе, моя проблема.

AfikDeri 27.01.2020 13:21

Ответ Бена Карпа кажется мне единственно верным.

Но поскольку мы используем функциональные способы, закрытие и HoC может принести пользу другому подходу:

const InjectWillmount = function(Node, willMountCallback) {
  let isCalled = true;
  return function() {
    if (isCalled) {
      willMountCallback();
      isCalled = false;
    }
    return Node;
  };
};

Тогда используйте это:

const YourNewComponent = InjectWillmount(<YourComponent />, () => {
  console.info("your pre-mount logic here");
});

Краткий ответ на ваш вопрос оригинал, как componentWillMount можно использовать с React Hooks:

componentWillMount - это устарело и считается устаревшим. Реагировать на рекомендация:

Generally, we recommend using the constructor() instead for initializing state.

Теперь в Крючок FAQ вы узнаете, что эквивалент конструктора класса для функциональных компонентов:

constructor: Function components don’t need a constructor. You can initialize the state in the useState call. If computing the initial state is expensive, you can pass a function to useState.

Итак, пример использования componentWillMount выглядит так:

const MyComp = () => {
  const [state, setState] = useState(42) // set initial value directly in useState 
  const [state2, setState2] = useState(createInitVal) // call complex computation

  return <div>{state},{state2}</div>
};

const createInitVal = () => { /* ... complex computation or other logic */ return 42; };

Вот так я моделирую конструктор в функциональных компонентах с помощью ловушки useRef:

function Component(props) {
    const willMount = useRef(true);
    if (willMount.current) {
        console.info('This runs only once before rendering the component.');
        willMount.current = false;        
    }

    return (<h1>Meow world!</h1>);
}

Вот пример жизненного цикла:

function RenderLog(props) {
    console.info('Render log: ' + props.children);
    return (<>{props.children}</>);
}

function Component(props) {

    console.info('Body');
    const [count, setCount] = useState(0);
    const willMount = useRef(true);

    if (willMount.current) {
        console.info('First time load (it runs only once)');
        setCount(2);
        willMount.current = false;
    } else {
        console.info('Repeated load');
    }

    useEffect(() => {
        console.info('Component did mount (it runs only once)');
        return () => console.info('Component will unmount');
    }, []);

    useEffect(() => {
        console.info('Component did update');
    });

    useEffect(() => {
        console.info('Component will receive props');
    }, [count]);


    return (
        <>
        <h1>{count}</h1>
        <RenderLog>{count}</RenderLog>
        </>
    );
}
[Log] Body
[Log] First time load (it runs only once)
[Log] Body
[Log] Repeated load
[Log] Render log: 2
[Log] Component did mount (it runs only once)
[Log] Component did update
[Log] Component will receive props

Конечно, в компонентах класса нет шагов Body, поэтому моделирование 1: 1 невозможно из-за различных концепций функций и классов.

Я не углублялся в ваш пример, но ваш первый фрагмент кода мне подходит. Спасибо!

SAndriy 24.04.2020 21:10

Точно и просто.

norman123123 25.09.2020 01:11

извините, как вы гарантируете, что все, что находится внутри if, будет выполнено до того, как компонент func будет смонтирован в dom?

Luk Aron 22.12.2020 04:05

Просто добавьте пустой массив зависимостей в useEffect, он будет работать как componentDidMount.

useEffect(() => {
  // Your code here
  console.info("componentDidMount")
}, []);

Это не ответ. Вопрос был в том, как использовать componentWillMount с хуками.

norman123123 25.09.2020 23:44

Вы можете взломать перехватчик useMemo, чтобы имитировать событие жизненного цикла componentWillMount. Просто сделать:

const Component = () => {
   useMemo(() => {
     // componentWillMount events
   },[]);
   useEffect(() => {
     // componentDidMount events
     return () => {
       // componentWillUnmount events
     }
   }, []);
};

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

Это работает, потому что useMemo не требует фактического возврата значения, и вам не нужно фактически использовать его как что-либо, но поскольку он запоминает значение на основе зависимостей, которые будут запускаться только один раз ("[]") и его поверх нашего компонента, он запускается один раз, когда компонент монтируется раньше всего.

Блестяще! Спасибо!

SrAxi 29.12.2020 13:50

Это может работать с текущей реализацией, но в документации React специально сказано не делать этого. Вы можете полагаться на useMemo как на оптимизацию производительности, а не как на семантическую гарантию.reactjs.org/docs/hooks-reference.html#usememo

Naliba 25.05.2021 17:28

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

jpmarks 15.06.2021 08:09

Для большинства это может быть ясно, но имейте в виду, что функция, вызываемая внутри тела функционального компонента, действует как beforeRender. Это не отвечает на вопрос о запуске кода на ComponentWillMount (до первого рендеринга), но поскольку он связан и может помочь другим, я оставляю его здесь.

const MyComponent = () => {
  const [counter, setCounter] = useState(0)
  
  useEffect(() => {
    console.info('after render')
  })

  const iterate = () => {
    setCounter(prevCounter => prevCounter+1)
  }

  const beforeRender = () => {
    console.info('before render')
  }

  beforeRender()

  return (
    <div>
      <div>{counter}</div>
      <button onClick = {iterate}>Re-render</button>
    </div>
  )
}

export default MyComponent

Реагировать на методы жизненного цикла в хуках

для простой визуальной ссылки следуйте этому изображению

Как вы можете просто видеть на картинке выше, для ComponentWillUnmount вам нужно сделать вот так

 useEffect(() => {
    return () => {
        console.info('componentWillUnmount');
    };
   }, []);

Спасибо! Не могли бы вы разместить здесь ссылку на исходную статью / пост? Качество картинки плохое [картинка шакального качества].

Dan 15.01.2021 11:11

Как было сказано в реагировать документ:

You might be thinking that we’d need a separate effect to perform the cleanup. But code for adding and removing a subscription is so tightly related that useEffect is designed to keep it together. If your effect returns a function, React will run it when it is time to clean up:

useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

поэтому единственное, что нам нужно, чтобы в хуках был componentWillUnmount, - это возвращать функцию внутри useEffect, как описано выше.

Учитывая это

  • componentWillMount устарел (1, 2, 3), и что предлагаемая замена выполняет код в constructor
  • код, выполняемый перед оператором возврата функционального компонента, который неявно запускается перед его рендерингом
  • грубый эквивалент монтирования компонента класса - это первоначальный вызов функционального компонента
  • цель состоит в том, чтобы выполнить некоторый код один раз, прежде чем пользовательский интерфейс будет обновлен

Решение было бы

Запуск функции в теле функционального компонента только один раз. Это может быть достигнуто с помощью useState, useMemo или useEffect, в зависимости от времени, необходимого для варианта использования.

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

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

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

Пример с useState:

const runOnceBeforeRender = () => {};

const Component = () => {
  useState(runOnceBeforeRender);

  return (<></>);
}

В качестве кастомного крючка:

const runOnceBeforeRender = () => {};

const useOnInitialRender = (fn) => {
  useState(fn);
}

const Component = () => {
  useOnInitialRender(fn);

  return (<></>);
};

Функция runOnceBeforeRender может дополнительно возвращать состояние, которое будет доступно сразу после первого рендеринга функции, не вызывая повторных рендерингов.

Итак, для хуков React я думаю, что нужно объявить вашу логику до того, как оператор return сможет работать. У вас должно быть состояние, для которого по умолчанию установлено значение true. В моем случае я вызвал состояние componentWillMount. Затем условие для запуска блока кода, когда это состояние истинно (блок кода содержит логику, которую вы хотите выполнить в вашем componentWillMount), последний оператор в этом блоке должен сбрасывать componentWillMountState на false (этот шаг важен, потому что если это не делается, будет происходить бесконечный рендеринг) Пример

// do your imports here

const App = () =>  {
  useEffect(() => {
    console.info('component did mount')
  }, [])
  const [count, setCount] = useState(0);
  const [componentWillMount, setComponentWillMount] = useState(true);
  if (componentWillMount) {
    console.info('component will mount')
    // the logic you want in the componentWillMount lifecycle
    setComponentWillMount(false)
  }
  
  return (
    <div>
      <div>
      <button onClick = {() => setCount(count + 1)}> 
        press me
      </button>
      <p>
        {count}
      </p>
      
      </div>
    </div>
  )
}

Возможно, это не точная альтернатива методу componentWillMount, но вот метод, который можно использовать для достижения той же цели, но с помощью useEffect:

Сначала инициализируйте объект, из которого вы извлекаете данные, пустым значением и определите метод useEffect:

const [details, setDetails] = useState("")

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

const retrieveData = () => {       
       getData()                  // get data from the server 
      .then(response => {
        console.info(response.data);
        setDetails(response.data)
      })
      .catch(e => {
        console.info(e);
      })
  }

Теперь в JSX, куда мы возвращаемся, добавляем теренарный оператор

*return(
  <div>
    { 
   details ? (
   <div class = "">
   <p>add Your Jsx Here</p>
</div>
): (
  <div>
<h4>Content is still Loading.....</h4>
</div>
)
}
  </div>
)*

Это гарантирует, что до тех пор, пока в объекте «детали» не будут данные, будет загружена вторая часть теренарного оператора, который, в свою очередь, запускает метод useEffect, который приводит к установке данных, полученных от сервера, в объекте «детали», следовательно, рендеринг основной JSX

Просто поместите массив зависимостей в React.useEffect () в качестве второго аргумента. Если какая-либо из зависимостей обновится, ловушка вызовет побочный эффект, который запустится и в конечном итоге обновит ваш компонент.

Компонент React - это функция, верно? Так что просто позвольте моменту componentWillMount быть телом функции перед оператором return.

function componentWillMountMomentIsHere() {
  console.info('component will mount')
}


function AnyComponent(){
  const [greeting, setGreeting] = useState('Hello')

  componentWillMountMomentIsHere()

  
  return <h1>{greeting}</h1>
}

Другие вопросы по теме