Effects

useEventCallback

A stable callback that always calls the latest closure.

Demo

0

captured
callback identity
stable

Usage

use-event-callback.tsxtsx
import { useState } from "react";
import { useEventCallback } from "hookli";

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

  const readLatest = useEventCallback(() => count);

  return (
    <div>
      <button onClick={() => setCount((prev) => prev + 1)}>{count}</button>
      <button onClick={() => alert(readLatest())}>Read latest</button>
    </div>
  );
}

API

useEventCallback.d.tsts
useEventCallback<Args extends unknown[], R>(fn: (...args: Args) => R): (...args: Args) => R

Parameters

NameTypeDefaultDescription
fn(...args: Args) => RThe function to keep current behind a stable reference. Calling during render throws — it is meant for event handlers and effects.

Returns

NameTypeDescription
callback(...args: Args) => RA memoized callback with an unchanging identity that always forwards to the latest fn.

Hook

The implementation, straight from hookli. Copy it, or install the package.

src/hooks/use-event-callback/use-event-callback.tstsx
import { useCallback, useRef } from "react";
import { useIsomorphicLayoutEffect } from "../use-isomorphic-layout-effect/use-isomorphic-layout-effect";

export const useEventCallback = <Args extends unknown[], R>(
  fn: (...args: Args) => R,
) => {
  const ref = useRef<(...args: Args) => R>(() => {
    throw new Error("Cannot call an event handler while rendering.");
  });

  useIsomorphicLayoutEffect(() => {
    ref.current = fn;
  }, [fn]);

  return useCallback((...args: Args) => ref.current(...args), [ref]);
};

View source on GitHub

Related hooks