Let say we have a simple counter app:
import { useEffect, useState } from "react";
function useStopwatch() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("useStopwatch");
const interval = setInterval(() => {
console.log(`Count = ${count}`);
setCount(count + 1);
}, 1000);
return () => clearInterval(interval);
}, [count]);
return count;
}
export default function App() {
const count = useStopwatch();
return (
<div className="App">
<h2>{count}</h2>
</div>
);
}
Everytime, `count` get mutated, `useStopwatch` will be trigger to re-run:
This is because, `useEffect` is deps on `count`.
The way we can solve the problem by decouple the `count` with `useEffect`
function useStopwatch() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("useStopwatch");
const interval = setInterval(() => {
console.log(`Count = ${count}`);
setCount((prev) => prev + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
return count;
}
setCount((prev) => prev + 1);
Custom hook is triggered much less times and we no longer deps on mutated state `count`