Недавно мне было поручено создать компонент уведомления, который на несколько секунд будет отображать сообщение, а затем исчезать. Это звучало нормально, пока я не узнал, что на самом деле нужно разместить массив сообщений.
Вот пример использования setTimeout()
с одиночным уведомлением:
Обратите внимание, что ловушка useEffect()
запускается всякий раз, когда message
изменяется. И message
устанавливается на ''
внутри setTimeout()
.
Чтобы обрабатывать несколько уведомлений, я начал с приведенного выше кода. У меня запускался хук useEffect()
всякий раз, когда messages
(теперь массив) изменялся. И messages
теперь был установлен в: messages
минус первый элемент внутри setTimeout()
. Выглядело это примерно так:
Что на самом деле происходит, когда вы запускаете это, немного удивляет:
- Нажата кнопка.
- Компоненты "Приложение" и "Уведомления" повторно визуализируют и отображают обновленный файл
messages
. clearTimeout()
выполняется.setTimeout()
выполняет закрытие.- Первый / единственный элемент удаляется из массива
messages
. setMessages()
выполнено.- Компонент приложения повторно отрисовывается, поскольку его состояние изменилось.
Обратите внимание, что компонент "Уведомления" не повторно обрабатывается.
Если вы удалите clearTimeout()
компонент уведомлений будет повторно отображен, но все станет беспорядочно. (Рекомендую попробовать!)
Итак, как нам это исправить?
Вот мое решение:
В этом решении ловушка useEffect()
по-прежнему выполняется при изменении messages
. Вы также заметите, что messages
все еще устанавливается внутри setTimeout()
.
Разница в том, что я перестаю ссылаться на messages
и изменять его внутри setTimeout()
. Вместо этого я создаю msgs
(копию messages
), изменяю его и устанавливаю messages
.
Что происходит в этом растворе:
- При начальной загрузке выполняется
useEffect()
, включаяclearTimeout()
. Ноmessages
иmsgs
равны[]
. - Нажата кнопка.
setMessages()
executes, что вызывает повторную визуализацию компонентов приложения и уведомлений.useEffect()
иclearTimeout()
execute.setTimeout()
выполняется, удаляя первый элемент изmsgs
и устанавливаяmessages
на измененныйmsgs
.- Изменение состояния вызывает повторную визуализацию компонентов приложения и уведомлений.
useEffect()
выполняется, и цикл продолжается до тех пор, пока условиеmsgs.length
не перестанет выполняться.
Надеюсь, это поможет любому, кто борется с подобной проблемой. Хотелось бы услышать ваши решения!