Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this an accurate polyfill of react's useEffectEvent?

Is this an accurate polyfill of react's upcoming useEffectEvent hook? Does it present any potential issues?

One part I was not sure about was whether the ref is guaranteed to have been updated prior to the returned function being used in any other effects. I think I'm okay on this front so long as I never use the rather esoteric useInsertionEffect anywhere else in my code, but I would like to confirm that.

function useEffectEvent(callback) {
  const fnRef = useRef(null)
  useInsertionEffect(() => {
    fnRef.current = callback
  }) 
  return (...args) => {
    return fnRef.current.apply(null, args)
  }
}
like image 936
dipea Avatar asked Jan 27 '26 16:01

dipea


1 Answers

I don't think the React team has proposed an official polyfill for useEffectEvent (at least I haven't seen it).

Having said that, you can see a polyfill inside the RFC for the now defunct useEvent which initially used useLayoutEffect. And in an early version of Separating Events from Effects, Dan Abramov showed an updated version that looked like this (no longer visible in the docs):

import { useRef, useInsertionEffect, useCallback } from 'react';

// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.

export function useEvent(fn) {
  const ref = useRef(null);
  useInsertionEffect(() => {
    ref.current = fn;
  }, [fn]);
  return useCallback((...args) => {
    const f = ref.current;
    return f(...args);
  }, []);
}

This polyfill uses useInsertionEffect. I believe that the reason for this choice is that insertion effects are the first to run (compared with useLayoutEffect and useEffect). So it is pretty safe to assume that the ref is updated before any of your other effects run.

Later on, the RFC for useEvent was shelved and useEffectEvent started to show in the docs. Nonetheless, the same polyfill can be reused to implement useEffectEvent since the exposed behaviour is the same.

Please note that with this polyfill, the hook returns a stable function (thanks to useCallback(..., [])), which might not be necessary but is more fool proof (in case the consumer adds the returned function to the dependencies of the effect by mistake).

If you want to understand more about the polyfill, I've blogged about it in: A look inside the useEvent polyfill from the new React docs.

like image 152
Gyum Fox Avatar answered Jan 29 '26 05:01

Gyum Fox