React Hooks
React Hooks cheat sheet with useState, useEffect, useRef, useContext, and custom hook patterns with practical code examples.
Other React Sheets
Sign in to mark items as known and track your progress.
Sign inState & Updates
Managing component state and triggering re-renders
useState
Local component state
// Basic state
const [count, setCount] = useState(0)
const [user, setUser] = useState({ name: 'John' })
// Update patterns
setCount(count + 1) // Direct update
setCount(prev => prev + 1) // Based on previous
setUser({ ...user, name: 'Jane' }) // Object updateuseReducer
Complex state logic with actions
// Define reducer
const reducer = (state, action) => {
switch (action.type) {
case 'increment': return { count: state.count + 1 }
case 'decrement': return { count: state.count - 1 }
case 'reset': return initialState
default: throw new Error()
}
}
// Use in component
const [state, dispatch] = useReducer(reducer, { count: 0 })
dispatch({ type: 'increment' })Side Effects
Handle side effects and external interactions
useEffect
Side effects and lifecycle
// After every render
useEffect(() => {
console.log('Rendered')
})
// Once on mount
useEffect(() => {
fetchData()
}, [])
// When dependencies change
useEffect(() => {
const timer = setTimeout(() => {}, 1000)
return () => clearTimeout(timer) // Cleanup
}, [count, id])useLayoutEffect
Synchronous DOM updates
// Runs synchronously after DOM mutations
useLayoutEffect(() => {
// Measure DOM
const height = ref.current.scrollHeight
// Adjust DOM before browser paint
ref.current.style.height = `${height}px`
}, [])Context & Refs
Share data and access DOM elements
useContext
Consume context values
// Create context
const ThemeContext = createContext()
// Provider component
<ThemeContext.Provider value={{ dark: true }}>
<App />
</ThemeContext.Provider>
// React 19: render <Context> directly as the provider
<ThemeContext value={{ dark: true }}>
<App />
</ThemeContext>
// Consume in any child
const theme = useContext(ThemeContext)
// React 19: use() can read context conditionally (inside if/loops)
const theme2 = use(ThemeContext)
// Custom hook pattern
function useTheme() {
const context = useContext(ThemeContext)
if (!context) throw new Error('No ThemeProvider')
return context
}useRef
Mutable refs and DOM access
// DOM reference
const inputRef = useRef(null)
<input ref={inputRef} />
inputRef.current.focus()
// Mutable value (doesn't trigger re-render)
const countRef = useRef(0)
countRef.current++ // No re-render
// Keep value between renders
const previousValue = useRef(undefined)
useEffect(() => {
previousValue.current = value
})Performance
Optimize re-renders and expensive operations
useMemo
Memoize expensive calculations
// Memoize expensive calculation
const expensiveValue = useMemo(() => {
return items.reduce((sum, item) => sum + item.value, 0)
}, [items]) // Recalculate when items change
// Memoize object/array to prevent re-renders
const options = useMemo(() => ({
color: 'blue',
size: 'large'
}), []) // Create onceuseCallback
Memoize functions
// Memoize function to prevent child re-renders
const handleClick = useCallback(() => {
doSomething(id)
}, [id]) // Recreate when id changes
// Without dependencies (never changes)
const handleSubmit = useCallback(() => {
dispatch({ type: 'submit' })
}, []) // dispatch is stableAdditional Hooks
Other useful built-in hooks
useImperativeHandle
Customize ref values
// Child component - ref is a normal prop in React 19 (no forwardRef)
function Child({ ref }) {
const inputRef = useRef(null)
useImperativeHandle(ref, () => ({
focus: () => inputRef.current.focus(),
clear: () => { inputRef.current.value = '' },
getValue: () => inputRef.current.value
}))
return <input ref={inputRef} />
}
// Parent component
const childRef = useRef(null)
childRef.current.focus()useId
Generate unique IDs
// Generate unique ID for accessibility
const id = useId()
return (
<>
<label htmlFor={id}>Name:</label>
<input id={id} />
</>
)
// Multiple IDs
const id = useId()
const emailId = `${id}-email`
const passwordId = `${id}-password`React 18+ Hooks
New concurrent features
// useTransition - mark updates as non-urgent
const [isPending, startTransition] = useTransition()
startTransition(() => {
setSearchQuery(input) // Non-urgent update
})
// useDeferredValue - defer updating a value
const deferredQuery = useDeferredValue(searchQuery)
// useDebugValue - custom hook debugging
function useCustomHook(value) {
useDebugValue(value ? 'Active' : 'Inactive')
return value
}React 19 Hooks
use, useActionState, useFormStatus & useOptimistic
New hooks introduced in React 19 for promises, forms, and optimistic UI.
// === use() - read a promise/context inside a component ===
import { use, Suspense } from 'react'
function UserName({ userPromise }: { userPromise: Promise<User> }) {
const user = use(userPromise) // Suspends until resolved
return <p>Hello, {user.name}</p>
}
// Wrap with Suspense
<Suspense fallback={<p>Loading...</p>}>
<UserName userPromise={fetchUser()} />
</Suspense>
// === useActionState - form/action state + pending flag ===
import { useActionState } from 'react'
async function submitAction(prev: State, formData: FormData) {
const name = formData.get('name')
// ... server call ...
return { ok: true, name }
}
function MyForm() {
const [state, formAction, isPending] = useActionState(submitAction, { ok: false })
return (
<form action={formAction}>
<input name="name" />
<button disabled={isPending}>{isPending ? 'Saving...' : 'Save'}</button>
</form>
)
}
// === useFormStatus - pending state of the enclosing <form> ===
import { useFormStatus } from 'react-dom'
function SubmitButton() {
const { pending } = useFormStatus() // Reads parent <form>
return <button disabled={pending}>{pending ? 'Sending...' : 'Submit'}</button>
}
// === useOptimistic - instant UI while async work runs ===
import { useOptimistic } from 'react'
function Likes({ count, like }: { count: number; like: () => Promise<void> }) {
const [optimisticCount, addOptimistic] = useOptimistic(
count,
(current, _: void) => current + 1,
)
return (
<button onClick={async () => { addOptimistic(); await like() }}>
👍 {optimisticCount}
</button>
)
}Custom Hook Patterns
Common custom hooks ready to use
Common Utility Hooks
Frequently used custom hooks
// Previous value
function usePrevious(value) {
const ref = useRef(undefined)
useEffect(() => { ref.current = value })
return ref.current
}
// Local storage
function useLocalStorage(key, initial) {
const [value, setValue] = useState(() => {
const saved = localStorage.getItem(key)
return saved ? JSON.parse(saved) : initial
})
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value))
}, [key, value])
return [value, setValue]
}
// Toggle
function useToggle(initial = false) {
const [on, setOn] = useState(initial)
const toggle = () => setOn(!on)
return [on, toggle]
}Rules & Best Practices
Essential rules and patterns
Hook Rules
Must follow these rules
// ✅ DO: Call at top level
function Component() {
const [state, setState] = useState()
useEffect(() => {}, [])
return <div />
}
// ❌ DON'T: Call conditionally
if (condition) {
useState() // ❌ Breaking rules
}
// ❌ DON'T: Call in loops
for (let i = 0; i < 5; i++) {
useState() // ❌ Breaking rules
}
// ✅ DO: Custom hooks start with 'use'
function useCustomHook() {
const [state, setState] = useState()
return [state, setState]
}