Mastering React Hooks: A Practical Guide with Real-World Examples
Introduction
React Hooks revolutionized functional components by enabling them to use state and other React features without writing classes. This guide provides a practical overview of commonly used hooks and their applications.
useState
The useState hook allows you to add state to functional components.
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
export default Counter;
This example demonstrates a simple counter component. useState(0) initializes the count state variable to 0. The setCount function is used to update the state, triggering a re-render.
useEffect
The useEffect hook lets you perform side effects in functional components. These can include data fetching, DOM manipulation, or setting up subscriptions.
import React, { useState, useEffect } from 'react';
function Example() {
const [data, setData] = useState(null);
useEffect(() => {
async function fetchData() {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const json = await response.json();
setData(json);
}
fetchData();
// Cleanup function (optional)
return () => {
// Perform cleanup here (e.g., cancel subscriptions)
};
}, []); // The empty dependency array ensures the effect runs only once on mount.
if (!data) {
return <p>Loading...</p>;
}
return (
<div>
<p>Title: {data.title}</p>
</div>
);
}
export default Example;
This example fetches data from an API endpoint when the component mounts. The empty dependency array [] ensures that the effect runs only once. A cleanup function can optionally be returned to prevent memory leaks.
useContext
The useContext hook allows you to access values from React Context without needing to use a Consumer component.
import React, { useContext } from 'react';
const ThemeContext = React.createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button style={{ backgroundColor: theme === 'dark' ? 'black' : 'white', color: theme === 'dark' ? 'white' : 'black' }}>
Themed Button ({theme})
</button>
);
}
export default ThemedButton;
This example demonstrates using useContext to access the current theme value.
useCallback
The useCallback hook memoizes a function. This can improve performance by preventing unnecessary re-renders of child components that receive the function as a prop.
import React, { useCallback } from 'react';
function MyComponent({ onButtonClick }) {
return (
<button onClick={onButtonClick}>Click Me</button>
);
}
function ParentComponent() {
const handleClick = useCallback(() => {
console.log('Button clicked!');
}, []); // Empty dependency array - function is only created once
return (
<MyComponent onButtonClick={handleClick} />
);
}
export default ParentComponent;
In this example, handleClick is only created once, so MyComponent will only re-render if its own props change.
useMemo
The useMemo hook memoizes the result of a calculation. Like useCallback, this helps optimize performance.
import React, { useMemo } from 'react';
function ExpensiveCalculation({ a, b }) {
const result = useMemo(() => {
// Simulate a very expensive calculation
console.log('Calculating...');
let i = 0;
while (i < 100000000) {
i++;
}
return a + b;
}, [a, b]); // Only recalculate if a or b changes
return (
<div>
Result: {result}
</div>
);
}
export default ExpensiveCalculation;
result will only be recalculated if a or b changes. Otherwise, the cached value is returned.
Conclusion
React Hooks provide a powerful and concise way to manage state and side effects in functional components. By understanding and utilizing these hooks effectively, you can write cleaner, more maintainable, and performant React applications.