Loading

Quipoin Menu

Learn • Practice • Grow

react / Custom Hooks
tutorial

Custom Hooks

Sometimes you find yourself writing the same logic in multiple components like fetching data, handling form inputs, or tracking window size. React lets you extract this reusable logic into your own custom Hook. Custom Hooks are JavaScript functions that start with "use" and can call other Hooks.

What is a Custom Hook?

A custom Hook is a regular JavaScript function that uses built-in Hooks (like `useState`, `useEffect`, etc.) to encapsulate reusable logic. It allows you to share logic between components without changing your component hierarchy.

Custom Hooks are a way to reuse stateful logic, not state itself. Each call to a custom Hook gets its own isolated state.

Rules for Custom Hooks

  • The name must start with "use" (e.g., `useFetch`, `useLocalStorage`).
  • It can call other Hooks (built-in or custom) inside it.
  • It's just a function you can pass arguments and return values.

Example 1: Custom Hook for Window Width
<!-- useWindowWidth.js -->
import { useState, useEffect } from 'react';

function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return width;
}

<!-- Using the custom hook -->
function MyComponent() {
  const width = useWindowWidth();
  return <p>Window width: {width}px</p>;
}

Example 2: Custom Hook for Fetching Data
<!-- useFetch.js -->
import { useState, useEffect } from 'react';

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

  useEffect(() => {
    setLoading(true);
    fetch(url)
      .then(res => {
        if (!res.ok) {
          throw new Error('Network response was not ok');
        }
        return res.json();
      })
      .then(data => {
        setData(data);
        setError(null);
      })
      .catch(err => {
        setError(err.message);
        setData(null);
      })
      .finally(() => setLoading(false));
  }, [url]);

  return { data, loading, error };
}

<!-- Using the hook -->
function UserProfile({ userId }) {
  const { data: user, loading, error } = useFetch(`/api/users/${userId}`);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error}</p>;
  return <div><h1>{user.name}</h1></div>;
}

Example 3: Custom Hook for Form Input
import { useState } from 'react';

function useInput(initialValue = '') {
  const [value, setValue] = useState(initialValue);

  const handleChange = (event) => {
    setValue(event.target.value);
  };

  return {
    value,
    onChange: handleChange,
    bind: { value, onChange: handleChange } <!-- Spread into input -->
  };
}

<!-- Using the hook -->
function LoginForm() {
  const username = useInput('');
  const password = useInput('');

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('Logging in with', username.value, password.value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" placeholder="Username" {...username.bind} />
      <input type="password" placeholder="Password" {...password.bind} />
      <button type="submit">Login</button>
    </form>
  );
}

Two Minute Drill

  • Custom Hooks let you extract and reuse stateful logic across components.
  • They are JavaScript functions that start with "use" and can call other Hooks.
  • Each component using a custom hook gets its own isolated state.
  • Use them to share logic like data fetching, form handling, subscriptions, etc.
  • They make your components cleaner and logic more reusable.

Need more clarification?

Drop us an email at career@quipoinfotech.com