Hone logo
Hone
Problems

Implement useTimeout React Hook

Create a custom React hook called useTimeout that allows developers to easily manage timeouts within their React components. This hook should provide a clear and reusable way to set a timeout that executes a callback function after a specified delay.

Problem Description

Your task is to implement a custom React hook named useTimeout in TypeScript. This hook will be responsible for managing JavaScript's setTimeout functionality within a React functional component. The hook should accept a callback function and a delay in milliseconds as arguments. It should also provide a way to clear the timeout.

Key Requirements:

  1. Accept Callback and Delay: The hook must accept a callback function (which takes no arguments) and a delay in milliseconds.
  2. Execute Callback: The provided callback function should be executed exactly once after the specified delay has elapsed.
  3. Clear Timeout: The hook should return a function that allows the caller to clear the timeout before it executes. This is crucial for preventing memory leaks and unexpected behavior when a component unmounts or the timeout is no longer needed.
  4. Handle Re-renders and Unmounting: The hook should gracefully handle component re-renders and ensure that timeouts are cleared when the component unmounts to avoid errors.
  5. Type Safety: Implement the hook using TypeScript for strong typing.

Expected Behavior:

When the useTimeout hook is called, it should set a timer. If the timer is not cleared using the returned clearTimeout function, the provided callback will be executed after the specified delay.

Examples

Example 1:

import React, { useState } from 'react';
import { useTimeout } from './useTimeout'; // Assuming useTimeout is in this file

function CounterComponent() {
  const [count, setCount] = useState(0);
  const [message, setMessage] = useState('');

  // Set a timeout to update the message after 2 seconds
  useTimeout(() => {
    setMessage('Timeout finished!');
  }, 2000);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <p>{message}</p>
    </div>
  );
}

Output (after 2 seconds):

The message state will update to "Timeout finished!".

Explanation:

The useTimeout hook is called with a callback that sets the message state. After 2000 milliseconds, this callback executes, updating the UI.

Example 2:

import React, { useState } from 'react';
import { useTimeout } from './useTimeout';

function DebounceInput() {
  const [inputValue, setInputValue] = useState('');
  const [debouncedValue, setDebouncedValue] = useState('');

  // Use useTimeout to debounce the input value update
  // The callback will only execute if the input doesn't change for 500ms
  const { resetTimeout } = useTimeout(() => {
    setDebouncedValue(inputValue);
  }, 500);

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setInputValue(e.target.value);
    // Reset the timeout every time the input changes
    resetTimeout();
  };

  return (
    <div>
      <input type="text" value={inputValue} onChange={handleChange} placeholder="Type here..." />
      <p>Debounced Value: {debouncedValue}</p>
    </div>
  );
}

Output:

As the user types, debouncedValue will only update 500ms after the user stops typing.

Explanation:

Each time handleChange is called, resetTimeout() is invoked, which effectively cancels the previous timeout and starts a new one. This ensures setDebouncedValue is only called after a period of inactivity.

Constraints

  • The delay parameter will be a non-negative number.
  • The callback parameter will be a function.
  • The hook should not introduce any performance bottlenecks.
  • The hook must be implemented as a functional hook, starting with use.

Notes

  • Consider using useRef to store the timeout ID.
  • Remember to clean up the timeout in the cleanup function of useEffect to prevent memory leaks.
  • The callback function should ideally be stable, meaning it doesn't change on every render if its dependencies haven't changed. However, for this challenge, focus on correct timeout management.
  • Think about how setTimeout and clearTimeout work in JavaScript and how they integrate with the React component lifecycle.
Loading editor...
typescript