1

Here is a popular useEvent shim:

function useEvent(callback) {
  const ref = useRef(() => {
    throw new Error("Cannot call an event handler while rendering.")
  })
  // Or useInsertionEffect if it's React 18
  useLayoutEffect(() => {
    ref.current = callback
  })
  return useCallback((...args) => ref.current(...args), []);
}

// Usage
function Component(props) {
  const [visible, setVisible] = useState(false)
  // props.onToggle may not be stable
  const onToggle = useEvent(props.onToggle)
  // But our onToggle is stable
  useEffect(() => onToggle(visible), [onToggle, visible])
  // ❌ Throws when used in the render phase
  onToggle(visible)
}

Source: https://tkdodo.eu/blog/refs-events-and-escape-hatches (gorgeous article by the way).

What I don't understand is why we need useLayoutEffect here, and why we can't set the ref value directly in the render function?

function useEvent(callback?) {
  const ref = useRef(callback)
  ref.current = callback
  return useCallback((...args) => ref.current(...args), [])
}
François Zaninotto
  • 7,068
  • 2
  • 35
  • 56

0 Answers0