Comprehensive collection of React hooks designed for modern React applications, offering utilities that extend beyond native React capabilities.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Safe wrappers for setTimeout and setInterval with automatic cleanup on component unmount.
Returns a wrapper function for setTimeout which automatically handles disposal when the component unmounts. This prevents memory leaks and errors from timeouts that fire after component unmount.
/**
* Returns a wrapper function for setTimeout which automatically handles disposal.
* @returns Object with setTimeout and clearTimeout methods that handle cleanup
*/
function useSetTimeout(): UseSetTimeoutReturnType;
interface UseSetTimeoutReturnType {
/** Safe setTimeout that auto-cleans on unmount */
setTimeout: (callback: () => void, duration: number) => number;
/** Clear a specific timeout */
clearTimeout: (id: number) => void;
}Usage Examples:
import { useSetTimeout } from "@fluentui/react-hooks";
function DelayedMessageComponent() {
const [message, setMessage] = useState('');
const { setTimeout, clearTimeout } = useSetTimeout();
const showDelayedMessage = () => {
setMessage('Loading...');
const timeoutId = setTimeout(() => {
setMessage('Message loaded after 2 seconds!');
}, 2000);
// Optionally clear the timeout early
// clearTimeout(timeoutId);
};
return (
<div>
<button onClick={showDelayedMessage}>Show Delayed Message</button>
<div>{message}</div>
</div>
);
}
// Auto-save functionality
function AutoSaveForm({ onSave, data }) {
const [isDirty, setIsDirty] = useState(false);
const { setTimeout, clearTimeout } = useSetTimeout();
const saveTimeoutRef = useRef<number>();
const handleChange = (newData) => {
setIsDirty(true);
// Clear existing save timeout
if (saveTimeoutRef.current) {
clearTimeout(saveTimeoutRef.current);
}
// Set new save timeout
saveTimeoutRef.current = setTimeout(() => {
onSave(newData);
setIsDirty(false);
}, 1000); // Save after 1 second of no changes
};
return (
<div>
<input onChange={(e) => handleChange(e.target.value)} />
{isDirty && <span>Unsaved changes...</span>}
</div>
);
}
// Notification with auto-dismiss
function NotificationComponent({ message, duration = 5000 }) {
const [isVisible, setIsVisible] = useState(true);
const { setTimeout } = useSetTimeout();
useEffect(() => {
if (isVisible && duration > 0) {
setTimeout(() => {
setIsVisible(false);
}, duration);
}
}, [isVisible, duration, setTimeout]);
if (!isVisible) return null;
return (
<div className="notification">
{message}
<button onClick={() => setIsVisible(false)}>×</button>
</div>
);
}Returns a wrapper function for setInterval which automatically handles disposal when the component unmounts. Prevents memory leaks from intervals that continue after component unmount.
/**
* Returns a wrapper function for setInterval which automatically handles disposal.
* @returns Object with setInterval and clearInterval methods that handle cleanup
*/
function useSetInterval(): UseSetIntervalReturnType;
interface UseSetIntervalReturnType {
/** Safe setInterval that auto-cleans on unmount */
setInterval: (callback: () => void, duration: number) => number;
/** Clear a specific interval */
clearInterval: (id: number) => void;
}Usage Examples:
import { useSetInterval } from "@fluentui/react-hooks";
// Real-time clock
function ClockComponent() {
const [time, setTime] = useState(new Date());
const { setInterval } = useSetInterval();
useEffect(() => {
const intervalId = setInterval(() => {
setTime(new Date());
}, 1000);
// Cleanup is handled automatically by useSetInterval
return () => {
// Optional: manual cleanup if needed before unmount
};
}, [setInterval]);
return (
<div>
Current time: {time.toLocaleTimeString()}
</div>
);
}
// Progress bar animation
function ProgressBarComponent({ duration = 10000 }) {
const [progress, setProgress] = useState(0);
const { setInterval, clearInterval } = useSetInterval();
const intervalRef = useRef<number>();
const startProgress = () => {
setProgress(0);
intervalRef.current = setInterval(() => {
setProgress(prev => {
const newProgress = prev + 1;
// Stop at 100%
if (newProgress >= 100) {
clearInterval(intervalRef.current!);
}
return Math.min(newProgress, 100);
});
}, duration / 100);
};
const stopProgress = () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
return (
<div>
<div>Progress: {progress}%</div>
<div
style={{
width: '200px',
height: '20px',
backgroundColor: '#f0f0f0',
border: '1px solid #ccc'
}}
>
<div
style={{
width: `${progress}%`,
height: '100%',
backgroundColor: '#007acc',
transition: 'width 0.1s ease'
}}
/>
</div>
<button onClick={startProgress}>Start</button>
<button onClick={stopProgress}>Stop</button>
</div>
);
}
// Polling for data updates
function DataPollingComponent({ url, pollInterval = 30000 }) {
const [data, setData] = useState(null);
const [isPolling, setIsPolling] = useState(false);
const { setInterval, clearInterval } = useSetInterval();
const pollIntervalRef = useRef<number>();
const fetchData = async () => {
try {
const response = await fetch(url);
const newData = await response.json();
setData(newData);
} catch (error) {
console.error('Failed to fetch data:', error);
}
};
const startPolling = () => {
setIsPolling(true);
fetchData(); // Initial fetch
pollIntervalRef.current = setInterval(() => {
fetchData();
}, pollInterval);
};
const stopPolling = () => {
setIsPolling(false);
if (pollIntervalRef.current) {
clearInterval(pollIntervalRef.current);
}
};
return (
<div>
<div>
<button onClick={startPolling} disabled={isPolling}>
Start Polling
</button>
<button onClick={stopPolling} disabled={!isPolling}>
Stop Polling
</button>
</div>
<div>Status: {isPolling ? 'Polling...' : 'Stopped'}</div>
{data && (
<div>
<h3>Latest Data:</h3>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
)}
</div>
);
}
// Heartbeat / Keep-alive mechanism
function HeartbeatComponent({ onHeartbeat, interval = 60000 }) {
const [isActive, setIsActive] = useState(false);
const [heartbeatCount, setHeartbeatCount] = useState(0);
const { setInterval, clearInterval } = useSetInterval();
const heartbeatRef = useRef<number>();
const startHeartbeat = () => {
setIsActive(true);
setHeartbeatCount(0);
heartbeatRef.current = setInterval(() => {
setHeartbeatCount(prev => prev + 1);
onHeartbeat();
}, interval);
};
const stopHeartbeat = () => {
setIsActive(false);
if (heartbeatRef.current) {
clearInterval(heartbeatRef.current);
}
};
return (
<div>
<div>
Heartbeat: {isActive ? 'Active' : 'Inactive'}
</div>
<div>
Count: {heartbeatCount}
</div>
<button onClick={startHeartbeat} disabled={isActive}>
Start Heartbeat
</button>
<button onClick={stopHeartbeat} disabled={!isActive}>
Stop Heartbeat
</button>
</div>
);
}