A robust React hook for managing asynchronous timers (setTimeout, setInterval, requestAnimationFrame) with automatic cleanup to prevent memory leaks.
npm install react-safe-timerssetTimeout, setInterval, requestAnimationFrame) upon component unmounting often leads to severe performance issues and console warnings. react-safe-timers provides a centralized hook useSafeTimers that wraps these native functions, ensuring all active timers are automatically cleared when the component unmounts. It eliminates the boilerplate code typically required for manual cleanup in useEffect.
setTimeout, setInterval, and requestAnimationFrame.
bash
npm install react-safe-timers
`
Usage
Import the useSafeTimers hook into your component. The hook returns safe versions of standard timer functions.
$3
`typescript
import React, { useState } from 'react';
import { useSafeTimers } from 'react-safe-timers';
export const NotificationComponent = () => {
const [isVisible, setIsVisible] = useState(false);
const { setSafeTimeout } = useSafeTimers();
const showNotification = () => {
setIsVisible(true);
// This timer will be automatically cleared if the component unmounts
// before the 3000ms duration completes.
setSafeTimeout(() => {
setIsVisible(false);
}, 3000);
};
return (
{isVisible && Operation Success}
);
};
`
$3
`typescript
import React, { useState, useEffect } from 'react';
import { useSafeTimers } from 'react-safe-timers';
export const TimerComponent = () => {
const [count, setCount] = useState(0);
const { setSafeInterval } = useSafeTimers();
useEffect(() => {
// Starts the interval immediately.
// No return cleanup function is required here; the hook handles it.
setSafeInterval(() => {
setCount(prev => prev + 1);
}, 1000);
}, [setSafeInterval]);
return Seconds elapsed: {count};
};
`
$3
`typescript
import React, { useRef, useEffect } from 'react';
import { useSafeTimers } from 'react-safe-timers';
export const AnimationComponent = () => {
const elementRef = useRef(null);
const { setSafeRAF } = useSafeTimers();
const animate = (timestamp: number) => {
if (elementRef.current) {
// Animation logic here
elementRef.current.style.transform = translateX(${timestamp % 500}px);
}
// Recursively call for the next frame
setSafeRAF(animate);
};
useEffect(() => {
setSafeRAF(animate);
}, [setSafeRAF]);
return ;
};
`
API Reference
The useSafeTimers hook returns an object containing the following methods:
$3
Schedules a function to run after a specified delay.
- Returns: A cleanup function that can be called to manually cancel the timeout.
$3
Schedules a function to run repeatedly at a specified interval.
- Returns: A cleanup function that can be called to manually cancel the interval.
$3
Schedules a function to run before the next repaint.
- Returns: A cleanup function that can be called to manually cancel the frame request.
$3
Instantly clears all active timers (timeouts, intervals, and animation frames) managed by the current hook instance. This is called automatically on unmount but can be used imperatively if needed.
Rationale
Consider the following standard React pattern which is prone to errors:
`typescript
// BAD PRACTICE
useEffect(() => {
const id = setTimeout(() => {
// If the component unmounts before this runs,
// this state update will trigger a React warning/error.
setData(result);
}, 1000);
// Developer often forgets this cleanup line:
// return () => clearTimeout(id);
}, []);
`
With react-safe-timers, the cleanup is intrinsic:
`typescript
// BEST PRACTICE
const { setSafeTimeout } = useSafeTimers();
useEffect(() => {
setSafeTimeout(() => {
// Safe to execute; will not run if component is unmounted.
setData(result);
}, 1000);
}, []);
``