apps/web/src/hooks/useStableCallback.ts

import { useLayoutEffect, useRef, useState } from "react";

/**
 * Only call it from event handlers and effects; during render it would see the
 * previous commit's `fn`. The forwarder is created once so its identity does not
 * depend on the React Compiler, and it keeps no render scope alive: V8 shares one
 * scope between all closures of a render.
 */
export function useStableCallback<Args extends ReadonlyArray<unknown>, Result>(
  fn: (...args: Args) => Result,
): (...args: Args) => Result {
  const latest = useRef(fn);
  useLayoutEffect(() => {
    latest.current = fn;
  });
  const [stable] = useState(
    () =>
      (...args: Args) =>
        latest.current(...args),
  );
  return stable;
}