DEV Community

Cover image for Stop Repeating Yourself: How Custom Hooks Will Change Your React Code Forever
Ilsa_S
Ilsa_S

Posted on

Stop Repeating Yourself: How Custom Hooks Will Change Your React Code Forever

Let's be real. Have you ever copied and pasted the same chunk of code between two different React components?

Maybe it was code to:

  • Fetch data from an API.

  • Manage a form's input values.

  • Listen to keyboard presses.

  • Connect to a websocket.

If you have, you've felt the pain. It works, but it's messy. And if you find a bug in that code, you have to remember to fix it in every single place you pasted it. Yuck.

What if there was a way to write that logic once and use it everywhere? There is. It's called a Custom Hook.

What is a Custom Hook, Really? (No Jargon)

Imagine you have a favorite power tool, like a drill. You don't build a new drill from scratch every time you need to put up a shelf. You just grab your drill from the toolbox and use it.

A Custom Hook is your personal power tool for React.
It's not a new React feature you have to install. It's just a JavaScript function whose name starts with "use" that can use other hooks inside it.

That's it. You're just making a function.

Let's Build a Tool Together: useLocalStorage
A super common need is to save something to the user's browser (like their username) so it doesn't disappear when they refresh the page.

The Messy Way (Without a Custom Hook):
You'd copy this same useState and useEffect code into every component that needs it

// Inside ComponentOne.js and ComponentTwo.js and... 😩
function MyComponent() {
  const [name, setName] = useState(() => {
    // Get the saved name from the browser when the component starts
    const savedName = localStorage.getItem('name');
    return savedName ? JSON.parse(savedName) : '';
  });

  useEffect(() => {
    // Save the name to the browser every time it changes
    localStorage.setItem('name', JSON.stringify(name));
  }, [name]);

  return <input value={name} onChange={e => setName(e.target.value)} />;
}
Enter fullscreen mode Exit fullscreen mode

The Clean Way (With a Custom Hook):
Let's build our useLocalStorage power tool.

Step 1: Make a new file: useLocalStorage.js

Step 2: Build your tool inside it.

// useLocalStorage.js
import { useState, useEffect } from 'react';

// 1. Our function name starts with 'use'. This makes it a Hook.
function useLocalStorage(key, initialValue) {
  // 2. We can use other Hooks inside our custom Hook! This is the magic.
  const [value, setValue] = useState(() => {
    // Get the saved value from the browser when the hook starts
    const savedValue = localStorage.getItem(key);
    return savedValue ? JSON.parse(savedValue) : initialValue;
  });

  useEffect(() => {
    // Save the value to the browser every time it changes
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  // 3. Return the value and the function to update it, just like useState does!
  return [value, setValue];
}

export default useLocalStorage;
Enter fullscreen mode Exit fullscreen mode

Step 3: Now, use your powerful new tool anywhere!

// Inside AnyComponent.js
import useLocalStorage from './useLocalStorage';

function AnyComponent() {
  // Just ONE line! Look how clean it is! ✨
  const [name, setName] = useLocalStorage('name', '');

  return <input value={name} onChange={e => setName(e.target.value)} />;
}
Enter fullscreen mode Exit fullscreen mode

What Just Happened?
We Wrote Logic Once: All the messy localStorage code is in one place.

1.We Made It Reusable: Any component in our app can now use this useLocalStorage hook.

2.We Made It Easy to Fix: If we find a bug, we fix it in one file (useLocalStorage.js), and it's automatically fixed in every component that uses it.

Your Turn: How to Start
1.Look for repetition. The next time you're about to copy code from one component to another... STOP.

2.Create a new file. Name it use[YourFeature].js (e.g., useApi.js, useToggle.js).

3.Move your repeated code into that function.
4.Return the values that your component needs (usually a value and a setter, just like useState).

Import and use it in your components. Feel like a wizard. 🧙‍♂️

Custom Hooks aren't about being a React genius. They're about being lazy in the smartest way possible: writing less code and making your life easier.

What's the first thing you'll turn into a custom hook? Share your idea below!

If you’d like to support my content, you can buy me a coffee here:
Buy Me a Coffee

Top comments (0)