Skip to content

React callback ref cleanup function #15176

Open
@k15a

Description

@k15a

At the time React added callback refs the main use case for them was to replace string refs. A lot of the callback refs looked like this:

<div ref={node => this.node = node} />

With the introduction of createRef and useRef this use case is pretty much replaced by these alternatives so the use case of callback refs will shift to advanced use cases like measuring DOM nodes.

It would be nice if you could return a cleanup function from the callback ref which is called instead of the callback with null. This way it will behave more like the useEffect API.

<div ref={node => {
  // Normal ref callback

  return () => {
    // Cleanup function which is called when the ref is removed
  }
}} />

This will be super helpful when you need to set up a Resize-, Intersection- or MutationObserver.

function useDimensions() {
  const [entry, setEntry] = useState()
  
  const targetRef = useCallback((node) => {
    const observer = new ResizeObserver(([entry]) => {
      setEntry(entry)
    })

    observer.observe(node)

    return () => {
      observer.disconnect()
    }
  }, [])

  return [entry, targetRef]
}

function Comp() {
  const [dimensions, targetRef] = useDimensions()

  return (
    <pre ref={targetRef}>
      {JSON.stringify(dimensions, null, 2)}
    </pre>
  )
}

Currently, if you want to implement something like this you need to save the observer into a ref and then if the callback ref is called with null you have to clean up the observer from the ref.

To be 99% backward compatible we could call both the callback ref with null and the cleanup function. The only case where it isn't backward compatible is if currently someone is returning a function and doesn't expect the function to be called.

function ref(node) {
  if (node === null) {
    return
  }

  // Do something

  return () => {
    // Cleanup something
  }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions