React Hooks revolutionized the way developers build React applications by allowing functional components to manage state and side effects. This guide explores advanced hooks and their practical applications.
Understanding Hooks
Hooks enable function components to use React features without writing a class. Advanced hooks help in optimizing performance, managing complex state logic, and handling side effects efficiently.
useReducer
is an alternative to useState
for managing complex state logic.
Example:
import { useReducer } from 'react'; const initialState = { count: 0 }; function reducer(state, action) { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; default: throw new Error(); } } function Counter() { const [state, dispatch] = useReducer(reducer, initialState); return ( <div> <p>Count: {state.count}</p> <button onClick={() => dispatch({ type: 'increment' })}>+</button> <button onClick={() => dispatch({ type: 'decrement' })}>-</button> </div> ); } export default Counter;
useContext
allows sharing state between components without prop drilling.
Example:
import { createContext, useContext, useState } from 'react'; const ThemeContext = createContext(); function ThemeProvider({ children }) { const [theme, setTheme] = useState('light'); return ( <ThemeContext.Provider value={{ theme, setTheme }}> {children} </ThemeContext.Provider> ); } function ThemedComponent() { const { theme, setTheme } = useContext(ThemeContext); return ( <div> <p>Current Theme: {theme}</p> <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}> Toggle Theme </button> </div> ); }
useMemo
memoizes expensive calculations.
Example:
import { useMemo, useState } from 'react'; function ExpensiveCalculation({ num }) { const squared = useMemo(() => { console.log('Calculating Square'); return num * num; }, [num]); return <p>Squared Value: {squared}</p>; }
useCallback
memoizes function instances.
Example:
import { useCallback, useState } from 'react'; function Button({ onClick }) { return <button onClick={onClick}>Click Me</button>; } function ParentComponent() { const [count, setCount] = useState(0); const increment = useCallback(() => setCount(count + 1), [count]); return ( <div> <p>Count: {count}</p> <Button onClick={increment} /> </div> ); }
useRef
stores values without causing re-renders.
Example:
import { useRef } from 'react'; function InputFocus() { const inputRef = useRef(null); return ( <div> <input ref={inputRef} type="text" /> <button onClick={() => inputRef.current.focus()}>Focus Input</button> </div> ); }
useLayoutEffect
runs synchronously after DOM mutations.
Example:
import { useLayoutEffect, useRef } from 'react'; function LayoutEffectComponent() { const divRef = useRef(null); useLayoutEffect(() => { console.log(divRef.current.offsetWidth); }); return <div ref={divRef}>Hello</div>; }