React js Advanced Custom Hooks Practice Questions with Solutions

Introduction

Advanced Custom Hooks help developers organize and reuse complex stateful logic across multiple React components. A custom Hook can combine built-in Hooks such as useState, useEffect, useMemo, and useCallback into a reusable API. Instead of repeating the same logic in different components, you can move it into a custom Hook and expose only the values and functions that components need. In this chapter, we will solve practical questions involving advanced custom Hook patterns. React js Advanced Custom Hooks practice questions with solutions to help you understand the concepts.

1. What is an Advanced Custom Hook in React (Advanced React Hooks)?

Answer:

An Advanced Custom Hook is a reusable JavaScript function that combines one or more React Hooks to solve a specific piece of application logic(Advanced React Hooks) .

For example, instead of repeating counter logic:

const [count, setCount] = useState(0);

you can create:

function useCounter() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(value => value + 1);
  };

  return {
    count,
    increment
  };
}

Then use it in a component:

function Counter() {
  const { count, increment } = useCounter();

  return (
    <div>
      <h2>{count}</h2>
      <button onClick={increment}>
        Increase
      </button>
    </div>
  );
}

The custom Hook hides the implementation details and provides a reusable interface.


2. How Can a Custom Hook Manage Multiple State Values?

Answer:

A custom Hook can manage multiple related pieces of state.

Example:

import { useState } from "react";

function useForm() {
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");

  return {
    name,
    email,
    setName,
    setEmail
  };
}

Use it inside a component:

function Registration() {
  const {
    name,
    email,
    setName,
    setEmail
  } = useForm();

  return (
    <form>
      <input
        value={name}
        onChange={e => setName(e.target.value)}
        placeholder="Name"
      />

      <input
        value={email}
        onChange={e => setEmail(e.target.value)}
        placeholder="Email"
      />
    </form>
  );
}

The Hook manages the form state while the component focuses on rendering the UI.


3. How Can a Custom Hook Accept Parameters?

Answer:

Custom Hooks can accept parameters just like normal JavaScript functions.

For example:

import { useState } from "react";

function useCounter(initialValue = 0) {
  const [count, setCount] = useState(initialValue);

  const increment = () => {
    setCount(value => value + 1);
  };

  const decrement = () => {
    setCount(value => value - 1);
  };

  return {
    count,
    increment,
    decrement
  };
}

Now different components can use different starting values:

const counterA = useCounter(0);
const counterB = useCounter(10);

Parameters make custom Hooks more flexible and reusable.


4. How Can a Custom Hook Use useEffect?

Answer:

A custom Hook can combine useState and useEffect to encapsulate synchronization or side-effect logic.

For example, a Hook that tracks the browser’s online status:

import { useEffect, useState } from "react";

function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(
    navigator.onLine
  );

  useEffect(() => {
    function handleOnline() {
      setIsOnline(true);
    }

    function handleOffline() {
      setIsOnline(false);
    }

    window.addEventListener("online", handleOnline);
    window.addEventListener("offline", handleOffline);

    return () => {
      window.removeEventListener("online", handleOnline);
      window.removeEventListener("offline", handleOffline);
    };
  }, []);

  return isOnline;
}

Use it like this:

function Status() {
  const isOnline = useOnlineStatus();

  return (
    <h2>
      {isOnline ? "Online" : "Offline"}
    </h2>
  );
}

The component does not need to manage event listeners itself.


5. How Can You Create a Reusable API Fetching Hook?

Answer:

A custom Hook can encapsulate common API fetching logic.

Example:

import { useEffect, useState } from "react";

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

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

    async function loadData() {
      try {
        setLoading(true);
        setError(null);

        const response = await fetch(url, {
          signal: controller.signal
        });

        if (!response.ok) {
          throw new Error("Failed to fetch data");
        }

        const result = await response.json();

        setData(result);
      } catch (err) {
        if (err.name !== "AbortError") {
          setError(err);
        }
      } finally {
        setLoading(false);
      }
    }

    loadData();

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

  return {
    data,
    loading,
    error
  };
}

The component can then use:

function Users() {
  const {
    data,
    loading,
    error
  } = useFetch("/api/users");

  if (loading) {
    return <p>Loading...</p>;
  }

  if (error) {
    return <p>Something went wrong.</p>;
  }

  return (
    <ul>
      {data?.map(user => (
        <li key={user.id}>
          {user.name}
        </li>
      ))}
    </ul>
  );
}

This pattern allows multiple components to reuse the same fetching behavior.


6. How Can a Custom Hook Manage Local Storage?

Answer:

A custom Hook can combine useState and useEffect to synchronize state with browser Local Storage.

Example:

import { useEffect, useState } from "react";

function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    const storedValue = localStorage.getItem(key);

    return storedValue !== null
      ? JSON.parse(storedValue)
      : initialValue;
  });

  useEffect(() => {
    localStorage.setItem(
      key,
      JSON.stringify(value)
    );
  }, [key, value]);

  return [value, setValue];
}

Use it like this:

function Theme() {
  const [theme, setTheme] = useLocalStorage(
    "theme",
    "light"
  );

  return (
    <button
      onClick={() =>
        setTheme(
          theme === "light" ? "dark" : "light"
        )
      }
    >
      Theme: {theme}
    </button>
  );
}

Now the component gets persistent state without directly handling localStorage.


7. How Can Custom Hooks Be Combined Together?

Answer:

One custom Hook can use another custom Hook.

For example:

function useCounter(initialValue = 0) {
  const [count, setCount] = useState(initialValue);

  const increment = () => {
    setCount(value => value + 1);
  };

  return {
    count,
    increment
  };
}

Another Hook can use it:

function useDoubleCounter() {
  const {
    count,
    increment
  } = useCounter();

  const double = count * 2;

  return {
    count,
    double,
    increment
  };
}

Then:

function App() {
  const {
    count,
    double,
    increment
  } = useDoubleCounter();

  return (
    <div>
      <p>Count: {count}</p>
      <p>Double: {double}</p>

      <button onClick={increment}>
        Increase
      </button>
    </div>
  );
}

This is called composing Hooks.

It allows complex behavior to be built from smaller reusable pieces.


8. How Can useCallback Be Used Inside an Advanced Custom Hook?

Answer:

useCallback can be useful when a custom Hook returns functions that should have a stable reference when their dependencies have not changed.(Advanced Custom Hooks)

Example

import {
  useCallback,
  useState
} from "react";

function useCounter() {
  const [count, setCount] = useState(0);

  const increment = useCallback(() => {
    setCount(value => value + 1);
  }, []);

  const decrement = useCallback(() => {
    setCount(value => value - 1);
  }, []);

  return {
    count,
    increment,
    decrement
  };
}

Here, increment and decrement keep stable function references between renders unless their dependencies change.

This can be useful when the returned functions are passed to memoized child components.

However, useCallback should not be added automatically to every function. It is primarily a performance optimization.


9. How Can an Advanced Custom Hook Handle Form Validation?

Answer:

A custom Hook can centralize form values, errors, and validation logic.

Example:

import { useState } from "react";

function useFormValidation() {
  const [form, setForm] = useState({
    name: "",
    email: ""
  });

  const [errors, setErrors] = useState({});

  function handleChange(e) {
    const { name, value } = e.target;

    setForm(previous => ({
      ...previous,
      [name]: value
    }));
  }

  function validate() {
    const newErrors = {};

    if (!form.name.trim()) {
      newErrors.name = "Name is required";
    }

    if (!form.email.includes("@")) {
      newErrors.email = "Valid email is required";
    }

    setErrors(newErrors);

    return Object.keys(newErrors).length === 0;
  }

  return {
    form,
    errors,
    handleChange,
    validate
  };
}

Use it in a component:

function RegistrationForm() {
  const {
    form,
    errors,
    handleChange,
    validate
  } = useFormValidation();

  function handleSubmit(e) {
    e.preventDefault();

    if (validate()) {
      console.log("Form submitted:", form);
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        name="name"
        value={form.name}
        onChange={handleChange}
        placeholder="Name"
      />

      <p>{errors.name}</p>

      <input
        name="email"
        value={form.email}
        onChange={handleChange}
        placeholder="Email"
      />

      <p>{errors.email}</p>

      <button type="submit">
        Submit
      </button>
    </form>
  );
}

The Hook keeps the validation logic reusable across multiple forms.

Client-side validation improves user experience but does not replace server-side validation.


10. Create a Practical Advanced Custom Hook for Search

Answer:

A reusable search Hook can manage the search text and return filtered results.

import {
  useMemo,
  useState
} from "react";

function useSearch(items, searchFields) {
  const [search, setSearch] = useState("");

  const filteredItems = useMemo(() => {
    const term = search.trim().toLowerCase();

    if (!term) {
      return items;
    }

    return items.filter(item =>
      searchFields.some(field =>
        String(item[field])
          .toLowerCase()
          .includes(term)
      )
    );
  }, [items, searchFields, search]);

  return {
    search,
    setSearch,
    filteredItems
  };
}

Example usage:

function ProductList({ products }) {
  const {
    search,
    setSearch,
    filteredItems
  } = useSearch(products, [
    "name",
    "category"
  ]);

  return (
    <div>
      <input
        value={search}
        onChange={e => setSearch(e.target.value)}
        placeholder="Search products..."
      />

      {filteredItems.map(product => (
        <div key={product.id}>
          <h3>{product.name}</h3>
          <p>{product.category}</p>
        </div>
      ))}
    </div>
  );
}

This Hook can now be reused for different searchable lists.

The filtering result is derived with useMemo; for small datasets, ordinary filtering may be simpler and sufficient.

Key Takeaways

  • Advanced Custom Hooks combine reusable stateful logic into a clean API.
  • Custom Hooks are JavaScript functions that use React Hooks.
  • A custom Hook can accept parameters.
  • A custom Hook can use multiple built-in Hooks.
  • Custom Hooks can use useState, useEffect, useMemo, useCallback, and other Hooks.
  • One custom Hook can use another custom Hook.
  • This composition helps build complex behavior from smaller reusable pieces.
  • API fetching logic can be moved into a custom Hook.
  • Local Storage synchronization can be encapsulated in a custom Hook.
  • Form state and validation can be reused through custom Hooks.
  • useCallback may help stabilize functions returned by a custom Hook when necessary.
  • useMemo can optimize expensive derived calculations when there is a real benefit.
  • Each call to a custom Hook has its own independent Hook state.
  • Custom Hooks share logic, not one shared state instance.
  • Custom Hooks should follow the Rules of Hooks.

FAQs

1. What is an Advanced Custom Hooks in React?

An Advanced Custom Hook is a reusable function that combines React Hooks to encapsulate more complex stateful or side-effect logic.

2. Can a custom Hook use another custom Hook?

Yes. Custom Hooks can call other custom Hooks, allowing developers to compose reusable behavior.

3. Does a custom Hook share state between components?

No. Each component calling a custom Hook gets its own independent state. The Hook shares logic, not automatically the same state.

4. Can custom Hooks accept parameters?

Yes. Custom Hooks can accept parameters just like regular JavaScript functions, making them reusable for different data or configurations.

5. Can a custom Hook use useEffect?

Yes. A custom Hook can use useEffect when the reusable logic needs synchronization with an external system or another side effect.

6. Should every piece of logic be moved into a custom Hook?

No. Custom Hooks are most useful when logic is reusable, complex enough to benefit from separation, or needs a clear reusable API. Very small one-off logic may be simpler inside the component.

7. What are the Rules of Hooks for custom Hooks?

Hooks must be called at the top level of React components or custom Hooks. They should not be called inside loops, conditions, nested functions, or ordinary non-Hook utility functions. Custom Hook names conventionally begin with use.

Written by Shubhranshu Shekhar, who has trained 20000+ students in coding.

Scroll to Top