Implement a useCounter hook that manages a counter state, with some additional convenience utility methods.
export default function Component() {const { count, increment, decrement, reset, setCount } = useCounter();return (<div><p>Counter: {count}</p><button onClick={increment}>Increment</button><button onClick={decrement}>Decrement</button><button onClick={reset}>Reset</button></div>);}
initialValue: number: Initial value of the counter state. If not provided, it should default to 0.The useCounter hook returns an object with the following properties:
count: number: The current counter valueincrement: () => void: A function to increment the counter valuedecrement: () => void: A function to decrement the counter valuereset: () => void: A function to reset the counter value to initialValue, or 0 if not providedsetCount: (value: number) => void: A function to set the counter value to value, it has the same signature as setStateuseCounter returns an object API around one numeric piece of state: the current count, relative updates, a reset action, and the raw setter.
The main correctness concern is updates that depend on previous state. increment and decrement should use the updater form of setCount so queued updates compose from the latest value instead of from a stale render.
useState is the only React primitive this hook really needs:
count lives in useState.increment and decrement use the updater form of the setter so they always calculate from the latest value.reset writes initialValue back into state.setCount is exposed directly so the hook still has the full flexibility of useState.The helper methods are just convenience wrappers around the same state transition model.
import { useState } from 'react';/*** @typedef {{* count: number,* increment: () => void,* decrement: () => void,* reset: () => void,* setCount: import('react').Dispatch<import('react').SetStateAction<number>>,* }} UseCounterReturn*//*** @param {number} [initialValue=0]* @returns {UseCounterReturn}*/export default function useCounter(initialValue = 0) {const [count, setCount] = useState(initialValue);return {count,increment: () => setCount((x) => x + 1),decrement: () => setCount((x) => x - 1),reset: () => setCount(initialValue),setCount,};}
increment and decrement avoids stale reads when multiple updates are queued close together.setCount lets consumers use either direct values or updater functions when the convenience helpers are not enough.In TypeScript, the only slightly non-obvious part is typing setCount, because it accepts both a direct value and an updater function. The type you want is Dispatch<SetStateAction<number>>, which can be imported from react.
If you prefer to be verbose, it essentially boils down to this.
type SetCount = (valueOrUpdater: number | ((previousValue: number) => number),) => void;
console.log() statements will appear here.