React Hooks
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.
1. useReducer: Managing Complex State
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;
2. useContext: Managing Global State
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>
);
}
3. useMemo: Performance Optimization
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>;
}
4. useCallback: Optimizing Function References
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>
);
}
5. useRef: Handling DOM and Persistent Values
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>
);
}
6. useLayoutEffect: Synchronous Effects
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>;
}