A custom hook is a function that calls hooks, and nothing more

There is no registration, no base class and no framework involvement. A function whose name starts with use and which calls other hooks is a custom hook, and that is the entire mechanism.

function useOrder(id) {
  const [order, setOrder] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    let live = true;
    fetchOrder(id).then(o => live && setOrder(o), setError);
    return () => { live = false; };
  }, [id]);

  return { order, error, loading: !order && !error };
}

This is what the whole feature is for: the subscription logic that was duplicated across four class components becomes one function that four components call. Each caller gets its own state — a hook is not a shared store, and two components calling useOrder have two independent copies. The use prefix is not decoration; it is how the linter knows to apply the rules, and a hook named otherwise silently loses that checking.