Преобразование componentDidUpdate в хуки

Я хотел бы переписать этот метод жизненного цикла в хук:

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) перед извлечением уведомления, оно все равно не сработает.

Вам не нужно добавлять [value] в useEffect вашего usePrevious? Примерно так: useEffect(() => { ... }, [value]). Также в другом useEffect, я думаю, вы должны добавить [notifications] к вашему useEffect. По крайней мере, это не должно называться больше, чем старое.

Kavoos 12.07.2019 11:59

Взгляните на usePrevious здесь: usehooks.com/usePrevious

Kavoos 12.07.2019 13:10
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
2
6 936
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете ограничить время срабатывания useEffect вторым параметром (массивом переменных).

useEffect(() => true, [variable]);

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

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

useEffect(() => {

  // your code

},[props.notifications])

Извините моя ошибка. Просто используйте props.notifications.

Jørgen 12.07.2019 12:50
Ответ принят как подходящий

Пара вопросов Я вижу одну проблему с вашим кодом хука:

  1. usePrevious никогда не будет обновляться после первого установленного значения

    Когда в useEffect не установлены зависимости, он запускается один раз и только один раз. В вашем случае, поскольку вы хотите отслеживать последний набор значений, вам нужно сделать это зависимостью от useEffect, то есть useEffect(() => ..., [value]), это заставит обратный вызов повторно запустить и обновить ссылку.

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

  2. Основной код обновления внутри 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 15.07.2019 10:38

@Peter, я просто следовал той же схеме раннего выхода, которую вы использовали в if выше (FWIW, я сам предпочитаю этот подход :))

James 15.07.2019 10:51

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