Я хотел бы переписать этот метод жизненного цикла в хук:
componentDidUpdate = prevProps => {
const { notifications, popNotification } = this.props;
if (prevProps.notifications.length >= notifications.length) return;
const [notification] = notifications;
popNotification(notification.id);
this.setState({
open: true,
message: notification.text,
variant: notification.variant,
});
};
Я знаю, что мне нужно использовать хук useEffect, но до сих пор он не работал. Вот что я придумал до сих пор:
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
const dispatch = useDispatch();
const popMessage = useCallback(id =>
dispatch(NotificationActions.popNotification(id))
);
const notifications = useSelector(state => state.notifications);
const previousValue = usePrevious(notifications.length);
useEffect(() => {
if (previousValue >= notifications.length) return;
// Extract notification from list of notifications
const [notification] = notifications;
popMessage(notification.id);
// Open snackbar
setSnackbar({
open: true,
message: notification.text,
variant: notification.variant,
});
});
Эта попытка не работает как старый метод, она вызывается чаще, чем старый метод, а также выдает TypeError: notification is undefined. Кроме того, если я добавлю if (notifications.length > 0) перед извлечением уведомления, оно все равно не сработает.
Взгляните на usePrevious здесь: usehooks.com/usePrevious





Вы можете ограничить время срабатывания useEffect вторым параметром (массивом переменных).
useEffect(() => true, [variable]);
При первой загрузке или когда переменные изменяют значение, эффект использования будет запущен, если вы ничего не укажете в качестве второго параметра, каждый повторный рендеринг будет запускать эффект использования.
Чтобы заменить componentDidUpdate на useEffect хук, передайте ему второй аргумент с массивом переменных, которые должны быть изменены от этого рендера к следующему, чтобы хук запустился.
useEffect(() => {
// your code
},[props.notifications])
Извините моя ошибка. Просто используйте props.notifications.
Пара вопросов Я вижу одну проблему с вашим кодом хука:
usePrevious никогда не будет обновляться после первого установленного значения
Когда в useEffect не установлены зависимости, он запускается один раз и только один раз. В вашем случае, поскольку вы хотите отслеживать последний набор значений, вам нужно сделать это зависимостью от useEffect, то есть useEffect(() => ..., [value]), это заставит обратный вызов повторно запустить и обновить ссылку.
Оказывается, я неправильно понял, что при повторном рендеринге функционального компонента он повторно запускает эффекты для хуков, вы можете игнорировать пункт 1.
Основной код обновления внутри useEffect, аналогичный пункту 1, запустится только один раз.
Опять же, ожидается, что код будет повторно запущен, когда счетчик уведомлений изменится, и поэтому его необходимо установить как зависимость useEffect(() => ..., [notifications.length])
Что касается упомянутой вами ошибки - notification is undefined, это говорит о том, что ваше состояние notifications либо не является допустимым массивом, либо массив пуст, проверьте результат useSelector(state => state.notifications)
Вот как я ожидаю, что это будет выглядеть на основе вашего кода
const dispatch = useDispatch();
const popMessage = useCallback(id =>
dispatch(NotificationActions.popNotification(id))
, []);
const notifications = useSelector(state => state.notifications);
const previousValue = usePrevious(notifications.length);
useEffect(() => {
if (!notifications.length || previousValue >= notifications.length) return;
// Extract notification from list of notifications
const [notification] = notifications;
if (!notification) return;
popMessage(notification.id);
// Open snackbar
setSnackbar({
open: true,
message: notification.text,
variant: notification.variant,
});
}, [notifications]);
Что ж, спасибо за обновление ответа и помощь мне. Я сделал это по-другому, но оба варианта хороши. Можете ли вы также удалить все свои комментарии под своим ответом? Я уже удалил свой для лучшей читабельности.
@Peter, я просто следовал той же схеме раннего выхода, которую вы использовали в if выше (FWIW, я сам предпочитаю этот подход :))
Вам не нужно добавлять
[value]в useEffect вашего usePrevious? Примерно так:useEffect(() => { ... }, [value]). Также в другом useEffect, я думаю, вы должны добавить[notifications]к вашему useEffect. По крайней мере, это не должно называться больше, чем старое.