Skip to the solution
MediumFrontend6 min read

What are React custom hooks and when should you use them?

820 views

The problem

Question presented to candidate: "What makes something a custom hook, and how do you decide when to extract one?"

What a strong answer should cover:

  • A custom hook is just a function whose name starts with use and which calls other hooks. There is no registration and no special API.
  • The naming convention is load-bearing: it is how the ESLint plugin knows to enforce the Rules of Hooks inside it.
  • It shares logic, never state. Every component calling the hook gets its own completely independent state — the single most important thing to say.
  • It obeys the Rules of Hooks: call it unconditionally, at the top level, from a component or another hook.
  • Why extract one: reusing stateful logic, making a component readable, or making the logic testable on its own.
  • What it replaced: HOCs and render props, without the wrapper component, prop collisions, or nesting.
  • Composition: hooks call other hooks, so behaviour composes flatly rather than by nesting.
  • Return shape: an array when order matters and the caller renames (like useState), an object when there are several named values.
  • When not to: a one-off used in a single place, or a wrapper that just renames a built-in hook.

Clarifying questions expected:

  • "Is this logic actually reused, or is extraction just for readability?" — both are valid, but they are different arguments.

Code / implementation expected: Yes — a custom hook with state and an effect, used by two components to show state independence.

  • hooks
  • reusability

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

6 min read · 9 sections

Try it in the playground

Open any example in the playground to run and change it.

ReactOne hook, two components, two entirely separate states
import { useState, useEffect, useCallback } from "react";

// A custom hook: a use-prefixed function calling other hooks. Nothing more.
function useCounter(start = 0, label = "") {
  const [count, setCount] = useState(start);

  // Stable identities so consumers can safely memoise.
  const inc = useCallback(() => setCount((c) => c + 1), []);
  const reset = useCallback(() => setCount(start), [start]);

  useEffect(() => {
    if (count > 0) console.log(label + " is now " + count);
  }, [count, label]);

  return { count, inc, reset };
}

// Hooks COMPOSE: a custom hook may call other custom hooks, and it stays flat.
function useDoubledCounter(start, label) {
  const counter = useCounter(start, label);
  return { ...counter, doubled: counter.count * 2 };
}

function Panel({ title, hook }) {
  const { count, doubled, inc, reset } = hook;
  return (
    <div style={{ border: "1px solid #ddd", borderRadius: 8, padding: 12, flex: 1 }}>
      <h4 style={{ margin: "0 0 8px" }}>{title}</h4>
      <p style={{ margin: "0 0 8px" }}>
        count: <strong>{count}</strong>
        {doubled !== undefined && <> · doubled: <strong>{doubled}</strong></>}
      </p>
      <button onClick={inc}>+1</button> <button onClick={reset}>reset</button>
    </div>
  );
}

function CounterA() {
  // Each call to the hook creates its OWN state. A and B never interact.
  return <Panel title="Component A" hook={useCounter(0, "A")} />;
}

function CounterB() {
  return <Panel title="Component B" hook={useCounter(0, "B")} />;
}

function CounterC() {
  return <Panel title="Component C (composed hook)" hook={useDoubledCounter(10, "C")} />;
}

export default function App() {
  return (
    <div style={{ padding: 24, fontFamily: "system-ui", lineHeight: 1.6 }}>
      <div style={{ display: "flex", gap: 12, marginBottom: 12 }}>
        <CounterA />
        <CounterB />
      </div>
      <CounterC />
      <p style={{ color: "#666", fontSize: 13 }}>
        Click +1 on A repeatedly. B does not move, and neither does C. The hook
        shares the logic; each component gets its own independent state. If you
        wanted them to share a value, that would be lifted state or Context.
      </p>
    </div>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 46 of 119 in React.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All React.js questions
Up nextMedium

How do you fetch data in React?

Continue