13. Advanced Hooks: useReducer, useContext, useRef
Level: IntermediateDuration: 28m
Why Advanced Hooks?
As your app grows, managing state with just useState can get messy. Advanced hooks like useReducer, useContext and useRef give us cleaner ways to manage complex logic and UI behavior.
useReducer – Manage Complex State
useReducer is useful when state updates depend on previous state or have multiple actions.
jsx
import { useReducer } from 'react'
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 }
case 'decrement':
return { count: state.count - 1 }
default:
return state
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 })
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
)
}
export default CounterCombining useReducer with useContext
You can combine both hooks to manage global state without prop drilling.
jsx
// StoreContext.jsx
import { createContext, useReducer } from 'react'
export const StoreContext = createContext()
const initialState = { user: null }
function reducer(state, action) {
switch (action.type) {
case 'login':
return { ...state, user: action.payload }
case 'logout':
return { ...state, user: null }
default:
return state
}
}
export function StoreProvider({ children }) {
const [state, dispatch] = useReducer(reducer, initialState)
return (
<StoreContext.Provider value={{ state, dispatch }}>
{children}
</StoreContext.Provider>
)
}useRef – Access DOM or Store Values
useRef lets us reference DOM elements or store values that persist across renders without causing re-renders.
jsx
import { useRef } from 'react'
function InputFocus() {
const inputRef = useRef()
function handleFocus() {
inputRef.current.focus()
}
return (
<div>
<input ref={inputRef} type="text" placeholder="Click button to focus" />
<button onClick={handleFocus}>Focus Input</button>
</div>
)
}
export default InputFocus- useRef doesn't trigger re-renders when updated
- Good for timers, DOM access and storing previous values
- Perfect for focus management
Mini Project Step
Add a notification system to your project using useReducer and useContext to manage alerts globally. Use useRef to focus on the input field when adding a new feature.
jsx
// notificationsReducer.js
export function notificationsReducer(state, action) {
switch (action.type) {
case 'add':
return [...state, action.payload]
case 'remove':
return state.filter((_, i) => i !== action.index)
default:
return state
}
}