Andrew's Digital Garden

Ref callbacks

Instead of an object returned by useRef, you can use a 'ref callback', which is a function passed to the ref attribute.

As of React 19 this also now has a [[20250219104717-ref-cleanup]] function.

<div ref={(node) => { console.log('Attached', node); return () => { console.log('Clean up', node) } }}>

This is often useful to avoid calling things in a [[20220815044638-useeffect]], as they don't trigger when a ref changes.

When the <div> DOM node is added to the screen, React will call your ref callback with the DOM node as the argument. When that <div> DOM node is removed, React will call your the cleanup function returned from the callback.

Note that this is also called when you pass a different ref callback.

React will also call your ref callback whenever you pass a different ref callback. In the above example, (node) => { ... } is a different function on every render. When your component re-renders, the previous function will be called with null as the argument, and the next function will be called with the DOM node.

Strict Mode will call an extra pass on these functions to test for resiliency. So in most cases you'll see four calls for this when developing.

You can use ref callbacks to manage a list of refs [[20250519010717-ref-lists]]

https://react.dev/reference/react-dom/components/common#ref-callback


#todo - how to share a ref?

const combineRefs = el => { internalRef.current = el if (typeof externalRef === 'function') { externalRef(el) } else { externalRef.current = el } }

Keep in mind the caveat around inline functions below

More complicated versions exist to handle using .current, multiple refs, Typescript, etc. It starts to get a little confusing and that's why NPM packages exist for it.


[[react]] [[reacthooks]]

Ref callbacks