H

Hooks

Type-safe React hooks including useState, useEffect, useRef, useReducer, and custom hooks.

Code

typescript
1import { useState, useEffect, useRef, useReducer, useCallback, useMemo } from "react";
2
3// useState with type inference
4function Counter() {
5 const [count, setCount] = useState(0); // inferred as number
6 const [name, setName] = useState<string | null>(null); // explicit union type
7
8 return (
9 <div>
10 <p>Count: {count}</p>
11 <button onClick={() => setCount((c) => c + 1)}>Increment</button>
12 <button onClick={() => setName("Alice")}>Set Name</button>
13 </div>
14 );
15}
16
17// useRef with proper typing
18function TextInput() {
19 const inputRef = useRef<HTMLInputElement>(null);
20 const renderCount = useRef(0); // mutable ref for values
21
22 useEffect(() => {
23 renderCount.current += 1;
24 });
25
26 const focusInput = () => {
27 inputRef.current?.focus(); // optional chaining for null safety
28 };
29
30 return (
31 <div>
32 <input ref={inputRef} type="text" />
33 <button onClick={focusInput}>Focus</button>
34 <p>Renders: {renderCount.current}</p>
35 </div>
36 );
37}
38
39// useReducer with typed state and actions
40interface State {
41 count: number;
42 error: string | null;
43}
44
45type Action =
46 | { type: "increment" }
47 | { type: "decrement" }
48 | { type: "reset"; payload: number }
49 | { type: "setError"; payload: string };
50
51function reducer(state: State, action: Action): State {
52 switch (action.type) {
53 case "increment":
54 return { ...state, count: state.count + 1, error: null };
55 case "decrement":
56 return { ...state, count: state.count - 1, error: null };
57 case "reset":
58 return { ...state, count: action.payload, error: null };
59 case "setError":
60 return { ...state, error: action.payload };
61 default:
62 return state;
63 }
64}
65
66function ReducerExample() {
67 const [state, dispatch] = useReducer(reducer, { count: 0, error: null });
68
69 return (
70 <div>
71 <p>Count: {state.count}</p>
72 {state.error && <p className="error">{state.error}</p>}
73 <button onClick={() => dispatch({ type: "increment" })}>+</button>
74 <button onClick={() => dispatch({ type: "decrement" })}>-</button>
75 <button onClick={() => dispatch({ type: "reset", payload: 0 })}>Reset</button>
76 </div>
77 );
78}
79
80// Custom hook with generics
81function useLocalStorage<T>(key: string, initialValue: T) {
82 const [storedValue, setStoredValue] = useState<T>(() => {
83 try {
84 const item = window.localStorage.getItem(key);
85 return item ? JSON.parse(item) : initialValue;
86 } catch {
87 return initialValue;
88 }
89 });
90
91 const setValue = (value: T | ((val: T) => T)) => {
92 const valueToStore = value instanceof Function ? value(storedValue) : value;
93 setStoredValue(valueToStore);
94 window.localStorage.setItem(key, JSON.stringify(valueToStore));
95 };
96
97 return [storedValue, setValue] as const;
98}
99
100// Usage
101function App() {
102 const [theme, setTheme] = useLocalStorage<"light" | "dark">("theme", "light");
103 return <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>{theme}</button>;
104}

Run this example locally

$ npm install react react-dom @types/react @types/react-dom