February 26, 2024 (9mo ago)
React's hooks API has revolutionized how we manage state and side effects in functional components. While built-in hooks like useState
and useEffect
are incredibly useful, custom hooks take this a step further by allowing you to encapsulate reusable logic and share it across multiple components.
Custom hooks are JavaScript functions that can use built-in React hooks to manage state and side effects. They provide a way to extract component logic into reusable functions, making your components cleaner and easier to maintain.
Let's start with a basic example of a custom hook for managing a counter.
1. Creating the Hook
Create a file named useCounter.js
(or .ts
if you’re using TypeScript) and define your custom hook:
import { useState } from 'react';
// Custom hook to manage counter state
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
const reset = () => setCount(initialValue);
return { count, increment, decrement, reset };
}
export default useCounter;
2. Using the Hook in a Component
Now that we have our custom hook, let’s use it in a component:
import React from 'react';
import useCounter from './useCounter';
function CounterComponent() {
const { count, increment, decrement, reset } = useCounter(10);
return (
<div>
<h1>Counter: {count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={reset}>Reset</button>
</div>
);
}
export default CounterComponent;
Custom hooks can also be used to handle side effects like data fetching. Here’s an example:
1. Creating the Hook
Create a file named useFetch.js
:
import { useState, useEffect } from 'react';
// Custom hook to fetch data from an API
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
if (!response.ok) throw new Error('Network response was not ok');
const result = await response.json();
setData(result);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
2. Using the Hook in a Component
Here’s how you might use useFetch
in a component:
import React from 'react';
import useFetch from './useFetch';
function DataFetchingComponent() {
const { data, loading, error } = useFetch('https://api.example.com/data');
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<h1>Data</h1>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
export default DataFetchingComponent;
use
(e.g., useCounter
, useFetch
) to follow React’s convention and make hooks recognizable.By building custom hooks, you can enhance the modularity and reusability of your React components. They help keep your code DRY (Don't Repeat Yourself) and improve the maintainability of your codebase. Happy coding!