marmelab/react-admin · error · Error

Cannot call an event handler while rendering.

Error message

Cannot call an event handler while rendering.

What it means

useDebouncedEvent wraps a callback so it can only be invoked after render, via a ref that is populated in a layout effect. The ref's initial value throws this error, which happens if the debounced handler is invoked during the render phase before React has committed and run the effect.

Source

Thrown at packages/ra-core/src/util/useDebouncedEvent.ts:24

// allow the hook to work in SSR
const useLayoutEffect =
    typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;

/**
 * Hook somewhat equivalent to useEvent, but with a debounce
 * Returns a debounced callback which will not change across re-renders unless the
 * callback or delay changes
 * @see https://reactjs.org/docs/hooks-faq.html#how-to-read-an-often-changing-value-from-usecallback
 * @see https://github.com/facebook/react/issues/14099#issuecomment-440013892
 */
export const useDebouncedEvent = <Args extends unknown[], Return>(
    callback: (...args: Args) => Return,
    delay: number
) => {
    // Create a ref that stores the debounced callback
    const debouncedCallbackRef = useRef<(...args: Args) => Return | undefined>(
        () => {
            throw new Error('Cannot call an event handler while rendering.');
        }
    );

    // Keep a stable ref to the callback (in case it's an inline function for instance)
    const stableCallback = useEvent(callback);

    // Whenever callback or delay changes, we need to update the debounced callback
    useLayoutEffect(() => {
        debouncedCallbackRef.current = debounce(stableCallback, delay);
    }, [stableCallback, delay]);

    // The function returned by useCallback will invoke the debounced callback
    // Its dependencies array is empty, so it never changes across re-renders
    return useCallback(
        (...args: Args) => debouncedCallbackRef.current(...args),
        []
    );
};

View on GitHub (pinned to 051f511bb0)

Solutions

  1. Move the call into an event handler, useEffect/useLayoutEffect, or async callback instead of render.
  2. Trigger initial invocations inside useEffect(() => { debouncedFn(); }, []).
  3. If a value is needed during render, compute it directly instead of calling the debounced handler.

Example fix

// before
const debounced = useDebouncedEvent(fn, 300);
debounced(); // during render -> throws
// after
const debounced = useDebouncedEvent(fn, 300);
React.useEffect(() => { debounced(); }, []);
Defensive patterns

Strategy: validation

Validate before calling

// Never call the debounced handler in render; invoke it in an effect:
React.useEffect(() => {
  debounced(args);
}, [deps]);

Try / catch

try {
  debounced(args);
} catch (e) {
  if (e instanceof Error && e.message.includes('while rendering')) {
    // move invocation to an effect/handler
  }
}

Prevention

When it happens

Trigger: Calling the debounced function directly during a component's render body or inside another component's render (e.g. debounceFn() at the top level of the component function) instead of inside an event handler, effect, or timeout.

Common situations: Developers invoking hooks-returned handlers immediately for 'initial fetch', calling them inside render-time computations, or in class-style lifecycle-like patterns that run during render.

Related errors


AI-assisted analysis of marmelab/react-admin@051f511bb0 (2026-08-30). Data as JSON: /api/errors/e488ff0c05eff60d. Report an issue: GitHub.