Mitchell
Posted on November 10, 2024
You can find all the code in this post on the repo Github.
Timer-related React custom hooks challenges
useCountdown()
import { useEffect, useRef, useState } from "react";
function useCountdown(initialValue) {
const [count, setCount] = useState(initialValue);
const [isActive, setIsActive] = useState(false);
const intervalRef = useRef(null);
function start() {
setIsActive(true);
}
function pause() {
setIsActive(false);
clearInterval(intervalRef.current);
}
function reset() {
setCount(initialValue);
setIsActive(false);
clearInterval(intervalRef.current);
}
useEffect(() => {
if (isActive && count > 0) {
intervalRef.current = setInterval(() => {
setCount((prevCount) => prevCount - 1);
}, 1000);
} else if (count === 0) {
clearInterval(intervalRef.current);
}
return () => clearInterval(intervalRef.current);
}, [count, isActive]);
return { count, isActive, start, pause, reset };
}
export default function App() {
const { count, isActive, start, pause, reset } = useCountdown(10);
return (
<div>
<h1>Countdown: {count}</h1>
<button onClick={start} disabled={isActive}>
Start
</button>
<button onClick={pause} disabled={!isActive}>
Pause
</button>
<button onClick={reset}>Reset</button>
{count === 0 && <p>Time's up!</p>}
</div>
);
}
useDebounce()
import { useState, useEffect } from "react";
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timerId = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(timerId);
}, [value, delay]);
return debouncedValue;
}
/* Usage example */
export default function App() {
const value = useDebounce(2, 2000);
return (
<div>
<p>Value: {value}</p>
</div>
);
}
useInterval()
import { useEffect, useRef, useState } from "react";
function useInterval(callbackFn, delay) {
const callbackFnRef = useRef(callbackFn);
useEffect(() => {
callbackFnRef.current = callbackFn;
}, [callbackFn]);
useEffect(() => {
const timerId = setInterval(() => {
callbackFnRef.current();
}, delay);
return () => clearInterval(timerId);
}, [delay]);
}
/* Usage example */
export default function App() {
const [count, setCount] = useState(0);
useInterval(() => {
setCount((prev) => prev + 1);
}, 1000);
return <div>Count: {count}</div>;
}
useThrottle()
import { useRef, useCallback, useState } from "react";
function useThrottle(callback, delay) {
const lastCall = useRef(0);
const timerId = useRef(null);
const throttledFunction = useCallback((...args) => {
const now = Date.now();
if (lastCall.current === 0 || now - lastCall.current >= delay) {
lastCall.current = now;
callback(...args);
} else if (!timerId.current) {
timerId.current = setTimeout(() => {
lastCall.current = Date.now();
callback(...args);
timerId.current = null;
}, delay - (now - lastCall.current));
}
}, [callback, delay]);
return throttledFunction;
}
export default function App() {
const [count, setCount] = useState(0);
const handleScroll = () => {
setCount((prevCount) => prevCount + 1);
console.log("Scroll event triggered", count);
};
const throttledScroll = useThrottle(handleScroll, 1000); // Throttle to 1 second
return (
<div
onScroll={throttledScroll}
style={{ height: "200vh", padding: "20px" }}
>
<h2>Scroll down to see throttling in action!</h2>
<p>Scroll Count: {count}</p>
</div>
);
}
useTimeout()
import { useEffect, useRef, useState } from 'react';
function useTimeout(callbackFn, delay) {
const callbackFnRef = useRef(callbackFn);
useEffect(() => {
callbackFnRef.current = callbackFn;
}, [callbackFn]);
useEffect(() => {
const timerId = setTimeout(() => {
callbackFnRef.current();
}, delay);
return () => clearTimeout(timerId);
}, [delay]);
}
/* Usage example */
export default function App() {
const [count, setCount] = useState(0);
useTimeout(() => {
setCount((prev) => prev + 1);
}, 1000);
return <div>Count: {count}</div>;
}
Reference
💖 💪 🙅 🚩
Mitchell
Posted on November 10, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.