Loading content…
Loading content…
Master hooks and modern React patterns
const [count, setCount] = useState(0);
// With type
const [name, setName] = useState<string>("");
// Multiple state variables
const [user, setUser] = useState({ name: "", email: "" });
// Functional update
setCount((prev) => prev + 1);
// Run once on mount
useEffect(() => {
console.log("Mounted");
}, []);
// Run on every render
useEffect(() => {
console.log("Rendered");
});
// Run when dependencies change
useEffect(() => {
fetchUser(userId);
}, [userId]);
// Cleanup
useEffect(() => {
const subscription = subscribe();
return () => subscription.unsubscribe();
}, []);
Senior Developer Wisdom
const ThemeContext = createContext<Theme | null>(null);
const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) throw new Error("useTheme must be in ThemeProvider");
return context;
};
// Usage
const Component = () => {
const { isDark } = useTheme();
return <div>{isDark ? "Dark" : "Light"}</div>;
};
interface State {
count: number;
error: string | null;
}
type Action =
| { type: "INCREMENT" }
| { type: "DECREMENT" }
| { type: "ERROR"; payload: string };
const reducer = (state: State, action: Action): State => {
switch (action.type) {
case "INCREMENT":
return { ...state, count: state.count + 1 };
case "DECREMENT":
return { ...state, count: state.count - 1 };
case "ERROR":
return { ...state, error: action.payload };
default:
return state;
}
};
const [state, dispatch] = useReducer(reducer, { count: 0, error: null });
const MemoizedChild = React.memo(({ onClick }) => {
return <button onClick={onClick}>Click</button>;
});
const Parent = () => {
// Without useCallback, new function every render
// const handleClick = () => console.log("Clicked");
// With useCallback, stable reference
const handleClick = useCallback(() => {
console.log("Clicked");
}, []);
return <MemoizedChild onClick={handleClick} />;
};
const expensive = useMemo(() => {
return complexCalculation(data);
}, [data]);
// Or for JSX
const memoizedComponent = useMemo(
() => <ExpensiveComponent data={data} />,
[data]
);
const inputRef = useRef<HTMLInputElement>(null);
const focusInput = () => {
inputRef.current?.focus();
};
return (
<div>
<input ref={inputRef} />
<button onClick={focusInput}>Focus</button>
</div>
);
Pro Tip
useRef is also useful for storing values that don't trigger re-renders when changed, like timers.// Good: Custom hook for data fetching
const useFetch = <T,>(url: string) => {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch(url);
setData(await res.json());
} catch (err) {
setError(err as Error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
};
// Usage
const { data: user, loading } = useFetch("/api/user");
// ❌ Wrong
const Component = ({ condition }) => {
if (condition) {
useState(0); // Breaks rules!
}
};
// ✅ Right
const Component = ({ condition }) => {
const [state, setState] = useState(condition ? 1 : 0);
};
Common Pitfall
// ❌ Bad: Creating new object every render
const Component = () => {
const config = { timeout: 5000 };
return <Child config={config} />;
};
// ✅ Good: Stable reference
const Component = () => {
const config = useMemo(() => ({ timeout: 5000 }), []);
return <Child config={config} />;
};
Hooks Mastery
useEffectMarking it complete updates your roadmap progress percentage.