DEV Community

Bukunmi Odugbesan
Bukunmi Odugbesan

Posted on

Coding Challenge Practice - Question 10

Today's task is to create a hook that easily uses setTimeout(callback, delay). Also:

  1. Reset the timer if delay changes.
  2. DO NOT reset the time if callback changes.

The boilerplate code:

export function useTimeout(callback: () => void, delay: number) {
  // your code here
}

// if you want to try your code on the right panel
// remember to export App() component like below

// export function App() {
//   return <div>your app</div>
// }

Enter fullscreen mode Exit fullscreen mode

The first step is to save the latest callback in a ref. This ensures that the timeout will always call the most recent version of the function.

const savedCallback = useRef(callback)
useEffect(() => {
savedCallback.current = callback
}, [callback])

Enter fullscreen mode Exit fullscreen mode

Next, the delay function. When the delay is null, the timer shouldn't run. Otherwise, it should set a new timeout when the delay changes. also, there should be a cleanup function to ensure old timeouts are cleared when the delay changes or the component unmounts.

useEffect(() => {
if(delay == null) return 
const id = setTimeout(() => {
savedcallback.current()
}, delay)
return () => clearTimeout(id)
}, [delay])

Enter fullscreen mode Exit fullscreen mode

To test it out, we will have 2 buttons that set the delay to 1s and 3s, respectively. The final code will look like this

import React, {useEffect, useRef, useState} from "react"

export function useTimeout(callback: () => void, delay: number) {
  // your code here
  const savedCallback = useRef(callback)

  useEffect(() => {
    savedCallback.current = callback;
  }, [callback])

  useEffect(() => {
    if(delay == null) return;

    const id = setTimeout(() => {
      savedCallback.current()
    }, delay);
    return () => clearTimeout(id)
  }, [delay])
}

// if you want to try your code on the right panel
// remember to export App() component like below

export function App() {
  const[count, setCount] = useState(0);
  const[delay, setDelay] = useState(3000);

  useTimeout(() => {
    console.log("Timeout fired:", count)
    setCount((c) => c + 1);
  }, delay)
  return (
    <div>
      <p> {count} </p>
      <button onClick={() => setDelay(1000)}> Set delay to 1s </button>
      <button onClick={() => setDelay(3000)}> Set delay to 3s </button>
    </div>
    )
}

Enter fullscreen mode Exit fullscreen mode

That's all folks!

Top comments (0)