Made by © Syed Arham Raza
BACK TO BLOGS
React

React Hooks Deep Dive: Beyond useState and useEffect

April 28, 20268 min read
React Hooks Deep Dive: Beyond useState and useEffect

Introduction

Most React developers are comfortable with useState and useEffect, but React offers a rich set of hooks that can dramatically improve your code quality and performance.

useReducer: Complex State Logic

When state logic gets complex, useReducer is your friend:

javascript
const initialState = { count: 0, step: 1 }; function reducer(state, action) { switch (action.type) { case 'increment': return { ...state, count: state.count + state.step }; case 'decrement': return { ...state, count: state.count - state.step }; case 'setStep': return { ...state, step: action.payload }; default: throw new Error('Unknown action'); } } function Counter() { const [state, dispatch] = useReducer(reducer, initialState); return ( <div> <p>Count: {state.count}</p> <button onClick={() => dispatch({ type: 'increment' })}> +{state.step} </button> </div> ); }

useMemo: Expensive Calculations

Avoid recalculating expensive values on every render:

javascript
function ProductList({ products, filter }) { const filteredProducts = useMemo(() => { console.log('Filtering products...'); return products.filter(p => p.name.toLowerCase().includes(filter.toLowerCase()) ); }, [products, filter]); return ( <ul> {filteredProducts.map(p => <li key={p.id}>{p.name}</li>)} </ul> ); }

useCallback: Stable Function References

Prevent unnecessary child re-renders:

javascript
function Parent() { const [count, setCount] = useState(0); const handleClick = useCallback(() => { setCount(c => c + 1); }, []); return <MemoizedChild onClick={handleClick} />; }

Custom Hooks: Reusable Logic

Extract and reuse stateful logic:

javascript
function useLocalStorage(key, initialValue) { const [value, setValue] = useState(() => { try { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch { return initialValue; } }); useEffect(() => { window.localStorage.setItem(key, JSON.stringify(value)); }, [key, value]); return [value, setValue]; } // Usage function App() { const [theme, setTheme] = useLocalStorage('theme', 'dark'); }

useRef: Beyond DOM References

useRef can store any mutable value:

javascript
function Timer() { const intervalRef = useRef(null); const [seconds, setSeconds] = useState(0); const start = () => { intervalRef.current = setInterval(() => { setSeconds(s => s + 1); }, 1000); }; const stop = () => clearInterval(intervalRef.current); return ( <div> <p>{seconds}s</p> <button onClick={start}>Start</button> <button onClick={stop}>Stop</button> </div> ); }

When to Use What?

HookUse Case
useStateSimple state values
useReducerComplex state with multiple sub-values
useMemoExpensive calculations
useCallbackStable function refs for child components
useRefMutable values, DOM refs
Custom HooksShared stateful logic

Conclusion

Mastering React hooks beyond the basics will make your code more performant, maintainable, and elegant. Start by identifying patterns in your code that could benefit from useReducer or custom hooks, and refactor gradually.

Syed Arham Raza

Syed Arham Raza

Developer & Tech Enthusiast

Tags

ReactHooksJavaScriptPerformance