React keeps adding crazy powerful hooks… and remembering them all feels like juggling flaming swords 🔥. I've been there before. This cheat sheet is your brain’s new best friend — just enough code to refresh your memory and keep you shipping like a pro. 🚀
📑 Table of Contents
- Basic Hooks (must-know)
- Additional Hooks (for optimization & complex state)
- React 18+ Hooks (new & shiny)
- Custom Hooks – your secret weapon
- Wrap-Up – your React Hooks cheat sheet
If you learn how to use all of these hooks perfectly the next time your PR get's reviewed the team lead's mouth would be dropped. Jokes aside, let's learn.
🟢 Basic Hooks (must-know)
useState
- your mini storage box (or getters and setters without tons of boilerplate)
This is where it all starts. useState
lets your component "remember" things between renderers. Think of it as a little box where you can store values.
const [count, setCount] = useState(0);
<button onClick={() => setCount(count + 1)}>
You clicked {count} times
</button>
Whe you call
setCount
, React re-renders the component with the new value.
Usage API:
const [value, setValue] = useState(initialValue); // 💡 Tip: You can pass a function as initialValue for expensive calculations
-
value
→ current state -
setValue
→ function to update it -
initialValue
→ starting value
useEffect
- sife effect manager.
At this point is where in almost all of the tutorials online you would hear "now this is where it gets a bit hacky", but don't worry, just with a bit of practice this hooks becomes like a second nature.
Want to fetch data, set up a subscription, or mess with document.title
? That's useEffect
. It runs after the component renders.
useEffect(() => {
console.log("Component mounted or updated!");
return () => {
console.log("Cleanup before unmount or next run");
};
}, [/* dependencies here */]);
Add dependencies in the array (
[userId]
) to control when it runs. Leave it empty ([]
) if you want it only once on mount.
Usage API:
useEffect(() => {
// side effect
return () => { /* cleanup */ }
}, [dependencies]);
- Runs after every render unless you control it with dependencies
- Empty array (
[]
) → run only once -
[dep1, dep2]
→ run when these change
useContext
- no more prop-drilling pain
I've tought a lot whether should i place this hook here or in the "advanced" section, as I rarely see anybody use it in their personal projects. If you do - I'm really impressed by your React skills, if not - this hook would take you far.
Tired of passing props down three... four... five levels deep? useContext
lets you read from a context directly.
const ThemeContext = React.createContext("light");
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
const theme = useContext(ThemeContext);
return <button className={theme}>I’m {theme} mode</button>;
}
Use it when multiple components need the same data (theme, user, language, etc.)
Usage API
const value = useContext(MyContext);
-
MyContext
→ the context object you created withReact.createContext
. -
value
→ whatever the nearest Provider is giving you
⚡ Advanced Hooks (for optimization & complex state)
useReducer
- the state machine
Now this is where the senior level react devs get separated from the juniors. Personally, whenever i see that somebody uses this hook i get goosebumps and give their repo a star. :D
When the state logic gets complicated, useReducer
steps in. It's like useState
but with superpowers. Perfect for forms, complex toggles, or anything with multiple actions.
function reducer(state, action) {
switch (action.type) {
case "increment": return { count: state.count + 1 };
case "decrement": return { count: state.count - 1 };
default: return state;
}
}
const [state, dispatch] = useReducer(reducer, { count: 0 });
<button onClick={() => dispatch({ type: "increment" })}>
{state.count}
</button>
Usage API:
const [state, dispatch] = useReducer(reducerFn, initialState);
-
state
→ current state -
dispatch
→ function to send actions -
reducerFn(state, action)
→ decides how state changes
useCallback
- memorized functions
Please, please, I beg you - use this instead of going trough every single component in your project just to rename a function. 😭
If you keep passing the same function dodwn to child components and triggering re-renders, useCallback
saves the day by memorizing it.
const memoizedHandler = useCallback(() => {
console.log("Runs only when deps change");
}, [dependency]);
Usage API:
const memoizedFn = useCallback(fn, [dependencies]);
- Returns the same function instance unless dependencies change
- Great for performance tuning
useMemo
- memorized values
Note: ts really helps with optimisations, dive even deeper into it, you won't regret - https://react.dev/reference/react/useMemo
Expensive calculations? Wrap them in useMemo
so they don't run every render.
const expensiveValue = useMemo(() => heavyCalculation(data), [data]);
Usage API:
const memoizedValue = useMemo(calcFn, [dependencies]);
- Only recalculates if dependencies change
- Think of it as a cached result
useRef
- the persistent box
ChatGPT's favourite hook when it comes to more eye-catching visuals :D
Need a value that sticks around but doesn't change re-renders? That's useRef
. Perfect for acessing DOM elements or keeping track of mutable stuff.
const inputRef = useRef(null);
<input ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>
Focus input
</button>
Usage API:
const ref = useRef(initialValue);
-
ref.current
→ mutable value (DOM node or custom value)
useImperativeHandle
- custom ref API
Sometimes you want a parent to call methods on a child. This hook lets you expose a custom API when using forwardRef
.
useImperativeHandle(ref, () => ({
focus: () => inputRef.current.focus()
}));
Usage API:
useImperativeHandle(ref, () => customObject, [dependencies]);
- Used with
forwardRef
- Lets parents call methods like
childRef.current.doSomething()
useLayoutEffect
- sync effect
Like useEffect
, but runs synchronously after DOM mutations (before the browser paints). Useful for measuring layout or scrolling.
useLayoutEffect(() => {
console.log("DOM is ready, before paint");
}, []);
Usage API:
useLayoutEffect(effectFn, [dependencies]);
- Blocks painting until it's done (⚠️ use carefully)
useDebugValue
– dev tools helper
Used in custom hooks to label values in React DevTools. Not for production code, just debugging.
function useFriendStatus(friendID) {
const isOnline = useSomeCustomHook(friendID);
useDebugValue(isOnline ? "Online" : "Offline");
return isOnline;
}
Usage API:
useDebugValue(value, formatFn?);
- Shows extra info in React DevTools
These hooks are your toolbox for performance & advanced state. You won’t use all of them daily, but knowing they exist = huge time saver.
🧪 React 18+ Hooks (new & shiny)
useId
– unique IDs without headaches
Needa stable ID for accessibility or forms? useId
generates unique IDs that won't change across renders.
const id = useId();
<label htmlFor={id}>Name</label>
<input id={id} />
Usage API:
const id = useId();
- Returns a stable, uniqe string
- Perfect for accessibility (
htmlFor
,aria-*
attributes)
useTransition
– smooth state updates
Mark updates as "non-blocing" to keep the UI responsive during heavy renders.
const [isPending, startTransition] = useTransition();
startTransition(() => {
setList(hugeNewList);
});
isPending && <Spinner />
Usage API:
const [isPending, startTransition] = useTransition();
-
isPending
→ true while transition is happening -
startTransition(callback)
→ wrap updates that can be delayed
useDeferredValue
- defer slow updates
Smooth out your UI by deferring non-critical updates.
const deferredSearch = useDeferredValue(searchQuery);
useEffect(() => {
fetchData(deferredSearch);
}, [deferredSearch]);
Usage API:
const deferredValue = useDeferredValue(value);
- Returns a slower-updating version of a value
- Useful for large lists, autocomplete, or filtering
useSyncExternalStore
- safe external subscriptions
Subscribe to external stores like Redux or custom stores safely, with React 18’s concurrent rendering.
const state = useSyncExternalStore(
store.subscribe,
store.getSnapshot
);
Usage API:
const state = useSyncExternalStore(subscribeFn, getSnapshotFn);
-
subscribeFn
→ called to listen for changes -
getSnapshotFn
→ returns the current state - Handles concurrent updates safely
useInsertionEffect
– style injection before paint
Mostly for CSS-in-JS libraries. Runs before DOM mutations, ensuring styles are applied before rendering.
useInsertionEffect(() => {
injectStyles(".btn { color: red }");
}, []);
Usage API:
useInsertionEffect(effectFn, [dependencies]);
- Runs synchronously before paint
- Great for styling libraries that need to inject CSS
🛠️ Custom Hooks – your secret weapon
Custom hooks are basically functions that use other hooks. They let you reuse logic across components without repeating yourself. Think of them as mini React utilities that you can plug in anywhere.
function useToggle(initial = false) {
const [value, setValue] = useState(initial);
const toggle = () => setValue(v => !v);
return [value, toggle];
}
// Usage in a component
function App() {
const [isOpen, toggleOpen] = useToggle(false);
return <button onClick={toggleOpen}>{isOpen ? "Open" : "Closed"}</button>;
}
Usage API:
const [value, toggle] = useToggle(initialValue);
-
value
→ current state -
toggle()
→ flips state from true → false or false → true
Example: useLocalStorage
– state that survives refreshes
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
return JSON.parse(localStorage.getItem(key)) ?? initialValue;
});
const setValue = (value) => {
setStoredValue(value);
localStorage.setItem(key, JSON.stringify(value));
};
return [storedValue, setValue];
}
// Usage
const [name, setName] = useLocalStorage("name", "Guest");
Wrap-Up – your React Hooks cheat sheet
And that’s a wrap! 🎉
You’ve now got a one-stop reference for all React hooks — from the essentials to the shiny new toys in React 18+. Keep this page handy, because next time someone asks for a “React hook example,” you’ll just wink and say, “Already got it.” 😎
Remember:
-
Basic hooks = your everyday tools (
useState
,useEffect
,useContext
) -
Advanced hooks = performance & complex state wizards (
useReducer
,useCallback
,useMemo
,useRef
) -
React 18+ hooks = concurrent rendering magic (
useTransition
,useDeferredValue
,useSyncExternalStore
) - Custom hooks = your secret weapons to reuse logic like a pro
If this cheat sheet saved you even a minute of Googling, consider buying me a coffee to keep the content flowing: ko-fi.com/deyan_sirakov ☕💖
Now go forth, hook like a hero, and never forget: React hooks are powerful, but your memory doesn’t have to be.
Top comments (0)