Как можно использовать крючок useEffect (или любой другой крючок, если уж на то пошло) для воспроизведения componentWillUnmount?
В традиционном компоненте класса я бы сделал что-то вроде этого:
class Effect extends React.PureComponent {
componentDidMount() { console.info("MOUNT", this.props); }
componentWillUnmount() { console.info("UNMOUNT", this.props); }
render() { return null; }
}
С крючком useEffect:
function Effect(props) {
React.useEffect(() => {
console.info("MOUNT", props);
return () => console.info("UNMOUNT", props)
}, []);
return null;
}
(Полный пример: https://codesandbox.io/s/2oo7zqzx1n)
Это не работает, так как функция «очистки», возвращенная в useEffect, фиксирует реквизиты в том виде, в каком они были во время монтирования, а не состояние реквизитов во время размонтирования.
Как я могу получить последнюю версию реквизита в useEffect очистке без, запускающей тело функции (или очистку) при каждом изменении реквизита?
Аналогичный вопрос не касается части доступа к последним реквизитам.
Состояние реагировать документы:
If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run.
Однако в этом случае я завишу от реквизита... но только для части очистки...
Это более общий вопрос, так как мне интересно, есть ли случаи, которые еще невозможно воспроизвести с помощью хуков. Но конкретным примером может быть сохранение реквизита в localStorage, IndexDB или аналогичном при размонтировании и чтение их обратно при монтировании. Я не думаю, что это следует делать при каждом изменении реквизита (например, при нажатии клавиши (если мы отображаем поля ввода)



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы можете использовать useRef и хранить реквизиты, которые будут использоваться в замыкании, таком как метод обратного вызова render useEffect return.
function Home(props) {
const val = React.useRef();
React.useEffect(
() => {
val.current = props;
},
[props]
);
React.useEffect(() => {
return () => {
console.info(props, val.current);
};
}, []);
return <div>Home</div>;
}
Однако лучший способ - передать второй аргумент useEffect, чтобы очистка и инициализация происходили при любом изменении желаемых реквизитов.
React.useEffect(() => {
return () => {
console.info(props.current);
};
}, [props.current]);
Большое спасибо! Использование useRef работает. Я также применил вашу технику к исходному примеру (упомянутому в вопросе) здесь: codeandbox.io/s/48w5m9pkwx для справочных целей.
Хотя это правильный ответ... он по-прежнему крайне неэргономичен, особенно когда вы также зависите от местного штата. Иногда лучше использовать компонент класса.
Я бы преобразовал это решение в пользовательский хук. Я вызываю свой useStateEffect, и основное отличие состоит в том, что зависимости передаются функции эффекта в качестве аргументов, и именно так вы получаете доступ к текущим значениям.
Вот ссылка на соответствующую документацию: reactjs.org/docs/hooks-effect.html#effects-with-cleanup. Из документов: «Если ваш эффект возвращает функцию, React запустит ее, когда придет время очистить:»
useLayoutEffect() — ваш ответ в 2021 году
useLayoutEffect(() => {
return () => {
// Your code here.
}
}, [])
Это эквивалентно ComponentWillUnmount.
В 99% случаев вы хотите использовать useEffect, но если вы хотите выполнить какие-либо действия перед размонтированием DOM, вы можете использовать предоставленный мной код.
Извините, но это не решает проблему, которую я поднял. Мне нужен доступ к реквизиту в момент размонтирования, и useLayoutEffect ведет себя так же, как useEffect в отношении запуска только при изменении зависимостей (пустой массив, который вы передали). Поэтому ваше решение имеет доступ только к начальным реквизитам FunctionComponent, а не к «последним реквизитам» во время размонтирования.
Ах извините! В то утро я не спал до 6, так что я не читал внимательно, ха-ха.
Я прочитал первые два вопроса и ответил на них. Да, вам нужно поместить переменную, на которой вы хотите сосредоточиться, в useRef для прямого доступа к новейшим изменениям. Функция возврата useEffect() фактически запускается после повторного рендеринга (делает DOM недоступным), в то время как функция возврата useLayoutEffect() запускается перед повторным рендерингом (делает DOM доступным). Это было самое чистое решение, которое я нашел, и я думал, что оно похоже на ваше. Возможно, это все равно поможет в будущем :)
useEffect(() => {
if (elements) {
const cardNumberElement =
elements.getElement('cardNumber') || // check if we already created an element
elements.create('cardNumber', defaultInputStyles); // create if we did not
cardNumberElement.mount('#numberInput');
}
}, [elements]);
useLayoutEffect отлично подходит для очистки прослушивателей событий на узлах DOM.
В противном случае с обычным useEffect ref.current будет нулевым при срабатывании ловушки времени.
Подробнее о реагирующих документах https://reactjs.org/docs/hooks-reference.html#uselayouteffect
import React, { useLayoutEffect, useRef } from 'react';
const audioRef = useRef(null);
useLayoutEffect(() => {
if (!audioRef.current) return;
const progressEvent = (e) => {
setProgress(audioRef.current.currentTime);
};
audioRef.current.addEventListener('timeupdate', progressEvent);
return () => {
try {
audioRef.current.removeEventListener('timeupdate', progressEvent);
} catch (e) {
console.warn('could not removeEventListener on timeupdate');
}
};
}, [audioRef.current]);
Прикрепить ссылку к узлу DOM компонента
<audio ref = {audioRef} />
Что вы хотите сделать, когда компонент размонтирован? Может быть, есть какой-то другой способ сделать это.