Не получается создать аналог ComponentDidUnmount в функциональном компоненте
Изучаю работу хука useEffect. Нужно продемонстрировать его работу по типу ComponentDidUnmount, чтобы некий код запускался при размонтировании компонента. Для этого я использую таймер, который запускается с помощью setInterval. В коде есть две ошибки, из-за которых ничего не работает должным образом.
Ошибка 1: не обновляется стейт таймера, он всегда = 0
Ошибка 2: после того, как закрываешь приложение, размонтирование не срабатывает: таймер продолжает работать, а консоль выдаёт ошибку "утечка памяти".
import React from 'react'
import {useState, useEffect} from 'react'
export const UseEffect: React.FC = () => {
const [count, setCount] = useState<number>(0)
const [intervalTest, setIntervalTest] = useState<NodeJS.Timeout>(
setTimeout(()=>{})
)
useEffect(()=>{
setIntervalTest(setInterval(()=>{
setCount(prev => prev + 1)
console.log(count)
// TODO: почему не происходит увеличение?
}, 2000))
}, [])
useEffect(()=>{
return () => {
clearInterval(intervalTest)
console.log('таймер count очищен')
}
}, [])
return (
<>
</>
)
}
Ошибка в консоли после попытки размонтирования:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
Ответы (1 шт):
Можно продемонстрировать например так:
import React, { useState, useEffect } from "react";
const UnmountableComponent = () => {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => setCount(count + 1), 1000);
return () => {
clearInterval(id);
}
}, [count, setCount])
return (
<>
<div>I am unmountableComponent</div>
<div>Count: {count}</div>
</>
)
}
export const App = () => {
const [show, setShow] = useState(true);
return (
<>
<button onClick={()=>setShow(!show)}>{show ? 'Hide' : 'Show'}</button>
{show && <UnmountableComponent/>}
</>
)
}
export default App;
В useEffect код запскается при монтировании компонента, возвращаемая функция выполняется после размонтирования. Чтобы работал таймер - нужно включить count в массив зависимостей, иначе он не будет обновляться. Работу useEffect можно продемонстрировать и без таймера например так:
import React, { useState, useEffect } from "react";
const UnmountableComponent = () => {
useEffect(() => {
console.log('I was mounted!')
return () => {
console.log('I was unmounted!')
}
}, [])
return (
<div>I am unmountableComponent</div>
)
}
export const App = () => {
const [show, setShow] = useState(true);
return (
<>
<button onClick={()=>setShow(!show)}>{show ? 'Hide' : 'Show'}</button>
{show && <UnmountableComponent/>}
</>
)
}
export default App;