Hone logo
Hone
Problems

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 timeout in milliseconds as an argument.
  • It should return a boolean state: isIdle.
  • isIdle should be false by default and when the user is active.
  • isIdle should become true after the timeout has elapsed without any detected user activity.
  • User activity includes, but is not limited to, mousemove, keydown, touchstart, and wheel events.
  • 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:

  1. When the hook is first used, isIdle should be false.
  2. If no user interaction occurs within the timeout period, isIdle should change to true.
  3. If any tracked user interaction occurs before the timeout expires, the timer should reset, and isIdle should remain false.
  4. If isIdle is true and user interaction occurs, isIdle should immediately become false.

Edge Cases:

  • What happens if the timeout is 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 timeout value provided to useIdle must 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 useRef to store the timeout ID for efficient cleanup.
  • You'll need to attach event listeners to a suitable element, typically document or window, to capture global user activity.
  • Think about which events are most appropriate to track for detecting "activity". mousemove, keydown, touchstart, and wheel are good starting points.
  • The setTimeout and clearTimeout functions in JavaScript will be your primary tools here.
Loading editor...
typescript