React useIdle Hook Implementation
Create a custom React hook, useIdle, that detects when a user has been inactive for a specified period. This hook is invaluable for implementing features like session timeouts, auto-saving forms, or displaying idle-state messages to the user.
Problem Description
Your task is to implement a TypeScript React hook named useIdle. This hook should accept a timeout value (in milliseconds) and return a boolean value indicating whether the user is currently considered idle. The hook needs to track user activity, such as mouse movement, keyboard presses, or touch events, and reset a timer. If the timer reaches the specified timeout without any activity, the hook should return true; otherwise, it should return false.
Key Requirements:
- The hook should accept a
timeoutin milliseconds as an argument. - It should return a boolean state:
isIdle. isIdleshould befalseby default and when the user is active.isIdleshould becometrueafter thetimeouthas elapsed without any detected user activity.- User activity includes, but is not limited to,
mousemove,keydown,touchstart, andwheelevents. - When activity is detected, the idle timer should be reset.
- The hook should clean up its event listeners when the component unmounts to prevent memory leaks.
Expected Behavior:
- When the hook is first used,
isIdleshould befalse. - If no user interaction occurs within the
timeoutperiod,isIdleshould change totrue. - If any tracked user interaction occurs before the
timeoutexpires, the timer should reset, andisIdleshould remainfalse. - If
isIdleistrueand user interaction occurs,isIdleshould immediately becomefalse.
Edge Cases:
- What happens if the
timeoutis 0 or negative? (Consider this for constraints). - The hook should work correctly even if the component is re-rendered.
Examples
Example 1: Basic Usage
import React, { useState, useEffect } from 'react';
import { useIdle } from './useIdle'; // Assuming your hook is in this file
function MyComponent() {
const IDLE_TIMEOUT = 5000; // 5 seconds
const isIdle = useIdle(IDLE_TIMEOUT);
return (
<div>
<h1>User Idle Detector</h1>
<p>
Your current status: {isIdle ? 'Idle' : 'Active'}
</p>
<p>
Move your mouse or type in an input field to become active.
</p>
<input type="text" placeholder="Type here..." />
</div>
);
}
Explanation: If the user does not interact with the page (move mouse, type, etc.) for 5 seconds, the "Your current status" will update to "Idle". Any interaction will reset the timer and update the status to "Active".
Example 2: Handling Different Idle States
import React, { useState, useEffect } from 'react';
import { useIdle } from './useIdle';
function Dashboard() {
const IDLE_TIMEOUT = 10000; // 10 seconds
const isIdle = useIdle(IDLE_TIMEOUT);
const [message, setMessage] = useState('Welcome! You are active.');
useEffect(() => {
if (isIdle) {
setMessage('You have been idle for a while. Logging out soon...');
// Potentially trigger a logout or other action here
} else {
setMessage('Welcome back! You are active.');
}
}, [isIdle]);
return (
<div>
<h2>Dashboard</h2>
<p>{message}</p>
<p>Activity will keep you logged in.</p>
</div>
);
}
Explanation:
The useIdle hook is used to trigger different UI messages based on the user's idle state. When isIdle becomes true after 10 seconds of inactivity, a "You have been idle..." message is displayed. Any activity resets isIdle and shows the "Welcome back..." message.
Constraints
- The
timeoutvalue provided touseIdlemust be a non-negative number. If a negative value is provided, it should be treated as 0 (or throw an error, depending on desired strictness - let's aim for treating it as 0 for simplicity). - The hook should not introduce significant performance overhead.
- The implementation should be in TypeScript.
Notes
- Consider using
useRefto store the timeout ID for efficient cleanup. - You'll need to attach event listeners to a suitable element, typically
documentorwindow, to capture global user activity. - Think about which events are most appropriate to track for detecting "activity".
mousemove,keydown,touchstart, andwheelare good starting points. - The
setTimeoutandclearTimeoutfunctions in JavaScript will be your primary tools here.