Hooks
| Hook | Purpose | Example |
|---|
useState | Local state | const [count, setCount] = useState(0) |
useEffect | Side effects, subscriptions | useEffect(() => { fetch() }, [dep]) |
useRef | Mutable ref, persists across renders | const ref = useRef(null) |
useMemo | Memoize computed value | const x = useMemo(() => compute(a), [a]) |
useCallback | Memoize function | const fn = useCallback(() => {}, [dep]) |
useReducer | Complex state logic | const [state, dispatch] = useReducer(reducer, init) |
useContext | Consume context | const value = useContext(MyContext) |
// useState - functional update for prev state
setCount(prev => prev + 1);
// useEffect - cleanup
useEffect(() => {
const sub = subscribe();
return () => sub.unsubscribe();
}, []);
// useReducer
const reducer = (state, action) => {
switch (action.type) {
case 'increment': return { count: state.count + 1 };
default: return state;
}
};
Component Patterns
// Composition
<Card>
<CardHeader title="Hi" />
<CardBody>{children}</CardBody>
</Card>
// Children
function Layout({ children }) {
return <div className="layout">{children}</div>;
}
// Render props
<DataFetcher url="/api" render={data => <List items={data} />} />
Event Handling
// Synthetic events, pass handler
<button onClick={handleClick}>Click</button>
// With args - use arrow or bind
<button onClick={() => handleDelete(id)}>Delete</button>
// Prevent default
<form onSubmit={e => { e.preventDefault(); submit(); }}>
Conditional Rendering
// && short-circuit
{isLoggedIn && <Dashboard />}
// Ternary
{loading ? <Spinner /> : <Content />}
// Early return
if (!user) return <Login />;
return <Profile user={user} />;
List Rendering with Keys
// Key must be stable, unique among siblings (not index for dynamic lists)
{items.map(item => (
<li key={item.id}>{item.name}</li>
))}
// Key on outermost element of map
{items.map(item => (
<Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.def}</dd>
</Fragment>
))}
Refs and DOM
const inputRef = useRef(null);
// Access DOM
inputRef.current?.focus();
// Forward ref to child
const FancyInput = forwardRef((props, ref) => (
<input ref={ref} {...props} />
));
Context API
// Create
const ThemeContext = createContext('light');
// Provide
<ThemeContext.Provider value="dark">
<App />
</ThemeContext.Provider>
// Consume
const theme = useContext(ThemeContext);
Performance
| Tool | When to use |
|---|
React.memo | Prevent re-render when props unchanged |
useMemo | Expensive computation, referential equality for deps |
useCallback | Stable fn reference for child props / deps |
// memo - shallow prop compare
const MemoChild = memo(({ name }) => <span>{name}</span>);
// useMemo - skip recompute
const sorted = useMemo(() => items.sort(...), [items]);
// useCallback - stable fn for useEffect/child
const handleClick = useCallback(() => doSomething(id), [id]);