Mastering React Hooks
React Hooks revolutionized how we write React components. Let's explore the most important hooks and advanced patterns.
useState: Managing State
The most basic hook for component state:
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}Advanced useState Patterns
Functional Updates:
// Use functional update when new state depends on previous
setCount(prevCount => prevCount + 1);Lazy Initial State:
// Expensive computation only runs once
const [state, setState] = useState(() => {
return expensiveComputation();
});useEffect: Side Effects
Handle side effects in your components:
import { useEffect } from 'react';
function DataFetcher({ userId }) {
const [data, setData] = useState(null);
useEffect(() => {
fetch(`/api/user/${userId}`)
.then(res => res.json())
.then(setData);
}, [userId]); // Re-run when userId changes
return <div>{data?.name}</div>;
}Cleanup Functions
useEffect(() => {
const subscription = subscribeToData();
// Cleanup function
return () => {
subscription.unsubscribe();
};
}, []);useContext: Global State
Share state without prop drilling:
import { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
const theme = useContext(ThemeContext);
return <div className={theme}>Toolbar</div>;
}useRef: Mutable References
Access DOM elements or store mutable values:
import { useRef } from 'react';
function TextInput() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current?.focus();
};
return (
<>
<input ref={inputRef} />
<button onClick={focusInput}>Focus</button>
</>
);
}useMemo: Performance Optimization
Memoize expensive computations:
import { useMemo } from 'react';
function ExpensiveComponent({ data }) {
const processedData = useMemo(() => {
return data.map(item => expensiveProcessing(item));
}, [data]);
return <List data={processedData} />;
}useCallback: Memoize Functions
Prevent unnecessary re-renders:
import { useCallback } from 'react';
function Parent() {
const [count, setCount] = useState(0);
// Function reference stays the same
const handleClick = useCallback(() => {
setCount(c => c + 1);
}, []);
return <Child onClick={handleClick} />;
}Custom Hooks
Create reusable logic:
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
// Usage
function App() {
const [name, setName] = useLocalStorage('name', '');
return (
<input
value={name}
onChange={e => setName(e.target.value)}
/>
);
}Advanced Patterns
useReducer for Complex State
import { useReducer } from 'react';
const 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 (
<>
<p>{state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</>
);
}Rules of Hooks
- Only call at the top level - Don't call hooks inside loops, conditions, or nested functions
- Only call from React functions - Call from components or custom hooks
Conclusion
React Hooks provide a powerful way to manage state and side effects in your components. Master these patterns to write cleaner, more maintainable React code.
Next Steps:
- Build custom hooks for common patterns
- Explore the React documentation
- Practice with real-world projects
Share this post

About Ankit Chaubey
Full-stack developer passionate about modern web technologies