/blog/mastering-react-custom-hooks-logic-reusability/ - zsh
user@portfolio ~ $

cat mastering-react-custom-hooks-logic-reusability.md

Mastering React Custom Hooks: Logic Reusability

Author: Aslany Rahim Published: November 20, 2025
Stop duplicating logic in your React components. Learn how to extract functionality into Custom Hooks to clean up your codebase.

One of the most powerful features introduced in React 16.8 was Hooks. While useState and useEffect are the bread and butter of modern React development, the real magic happens when you compose them into Custom Hooks.

If you find yourself writing the same useEffect code in multiple components—perhaps to fetch data or listen to window resizing events—it is time to refactor.

The Anatomy of a Custom Hook

A custom hook is simply a JavaScript function whose name starts with "use" and that may call other hooks. Let's look at a practical example: Data Fetching.

The Problem: Repetitive Fetch Logic

In a typical component, you might see this:

const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
  fetch('https://api.example.com/data')
    .then(res => res.json())
    .then(data => {
      setData(data);
      setLoading(false);
    })
    .catch(err => {
      setError(err);
      setLoading(false);
    });
}, []);

Writing this in every component is tedious and violates the DRY (Don't Repeat Yourself) principle.

The Solution: useFetch

Let's extract this into a hook file useFetch.js:

import { useState, useEffect } from 'react';

const useFetch = (url) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const abortCont = new AbortController();

    fetch(url, { signal: abortCont.signal })
      .then(res => {
        if (!res.ok) {
          throw Error('Could not fetch the data for that resource');
        }
        return res.json();
      })
      .then(data => {
        setData(data);
        setLoading(false);
        setError(null);
      })
      .catch(err => {
        if (err.name === 'AbortError') {
          console.log('fetch aborted');
        } else {
          setLoading(false);
          setError(err.message);
        }
      });

    return () => abortCont.abort();
  }, [url]);

  return { data, loading, error };
}

export default useFetch;

Implementing the Hook

Now, your component becomes significantly cleaner:

import useFetch from './useFetch';

const BlogList = () => {
  const { data: blogs, loading, error } = useFetch('https://api.example.com/blogs');

  return (
    <div className="blog-list">
      { error && <div>{ error }</div> }
      { loading && <div>Loading...</div> }
      { blogs && <BlogList blogs={blogs} /> }
    </div>
  );
}

Advanced Use Cases

Custom hooks aren't just for data. You can use them for:

  1. Form Handling: useForm to manage input state and validation.
  2. Media Queries: useMediaQuery to conditionally render layouts based on screen size.
  3. Local Storage: useLocalStorage to sync state automatically with the browser's storage.

Conclusion

Custom hooks allow you to separate logic from UI. By moving complex logic into hooks, your components become purely presentational, making them easier to read, test, and maintain.

27 views
0 comments

Comments (0)

Leave a Comment

No comments yet. Be the first to comment!

Related Posts

React Native Navigation: Stack vs. Tab vs. Drawer

Unlike the web, mobile apps don't have a URL bar. We explore how to structure your mobile app using React …

November 28, 2025

React Native CLI vs Expo: Which Should You Choose in 2025?

Starting a mobile project? The choice between "Bare" React Native and Expo can make or break your timeline. We break …

November 23, 2025

user@portfolio ~ $ _