Вам не нужно добавлять или удалять прослушиватели событий в каждом рендере, и добавление их только один раз, как и прежде, вполне возможно, если использовать useEffect с пустым массивом в качестве второго аргумента.Что-то вроде:
useEffect(() => {
// your didMount code here
return () => {
// your willUnmount code here
}
}, [])
Проблема
Ваша проблема заключается в том, что, поскольку функция запускается только один раз, значения, доступные из нее (такие как реквизиты или другие внешние области видимости)переменные) не будут обновляться при их изменении.
Например:
const [foo, setFoo] = setState(1)
useEffect(() => {
const id = window.setInterval(() => console.log(foo), 1000)
return () => window.clearInterval(id)
}, [])
// ...
setFoo(2)
Этот код всегда будет печатать 1, даже после вызова setFoo, поскольку функция привязана к старомузначение foo.
Рекомендованное решение
Когда вам нужно только обновлять какое-то состояние на основе самого себя и другого значения, лучшим вариантом будет использование редуктора с useReducer.Вы можете использовать диспетчеризацию из функции useEffect (или из любого другого места), и редуктор будет вызываться с обновленным состоянием, что позволяет ему читать его и обновлять по мере необходимости.Просто передайте любую новую информацию о самом действии.
В случае использования вы просто отправите соответствующую информацию о событии и получите редуктор для обработки обновлений.
Другие варианты
События реагирования
Если вы можете использовать стандартные события реакции вместо какого-либо addEventListener, вам не придется об этом думать, потому что функция будет обновляться при каждом рендеринге, без каких-либо действий со стороны вашегочасть.Вы можете передавать функции как реквизиты, чтобы они тоже использовались от дочернего компонента.
Refs
Вместо этого вы можете использовать ref, потому что они всегда возвращают один и тот же объект, изменяя его вместо созданияновый.Это позволяет любой функции, имеющей доступ к ref, прочитать текущее значение.
Пример:
const fooRef = useRef(1)
fooRef.current = foo
useEffect(() => {
const id = window.setInterval(() => console.log(fooRef.current), 1000)
return () => window.clearInterval(id)
}, [])
// ...
fooRef.current = 2
Вы можете использовать ref для значений или даже использовать его для функции, котораяВы бы позвонили из обработчика событий.Это не чистый путь, но вы можете заставить его работать.