no-leaked-timeout
Enforces that every 'setTimeout' in a component or custom hook has a corresponding 'clearTimeout'.
Full Name in eslint-plugin-react-web-api
react-web-api/no-leaked-timeoutFull Name in @eslint-react/eslint-plugin
@eslint-react/web-api-no-leaked-timeoutPresets
web-api
recommended
recommended-typescript
recommended-type-checked
strict
strict-typescript
strict-type-checked
Rule Details
Scheduling a timeout within the setup function of useEffect without canceling it in the cleanup function can lead to unwanted setTimeout callback executions and may also result in stale values captured by previous renders' effects after each subsequent re-render.
Examples
Setting timeout without cleanup in useEffect
import React, { useEffect, useState } from "react";
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
// Problem: A 'setTimeout' created in 'useEffect' must be cleared in the cleanup function.
const timeoutId = setTimeout(() => console.log(count), 1000);
}, []);
return null;
}Clearing timeout in useEffect cleanup
import React, { useEffect, useState } from "react";
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
// Recommended: Store the timeout ID
const timeoutId = setTimeout(() => console.log(count), 1000);
// Recommended: Clear the timeout in the cleanup function
return () => clearTimeout(timeoutId);
}, []);
return null;
}Versions
Resources
Further Reading
See Also
react-web-api/no-leaked-event-listener
Enforces that everyaddEventListenerin a component or custom hook has a correspondingremoveEventListener.react-web-api/no-leaked-fetch
Enforces that everyfetchin a component or custom hook has a correspondingAbortControllerabort in the cleanup function.react-web-api/no-leaked-interval
Enforces that everysetIntervalin a component or custom hook has a correspondingclearInterval.react-web-api/no-leaked-resize-observer
Enforces that everyResizeObservercreated in a component or custom hook has a correspondingResizeObserver.disconnect().