question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Share ref with multiple ref handlers

See original GitHub issue

Before React 16.3 we were able to proxy the same element ref to multiple listeners, for example, to grab hold of the element for internal purposes and also expose it publicly, like so:

class MyComponent extends Component {
  attachRef = el => {
    this.buttonEl = el;
    this.props.buttonRef(el);
  }

  // Do something with `this.buttonEl`

  render () {
    return <button ref={this.attachRef}>Button</button>;
  }
}

After React 16.3 this is more complicated as the ref prop can be a function or an object:

class MyComponent extends Component {
  buttonRef = React.createRef();

  attachRef = el => {
    this.buttonRef.current = el;
    
    if (typeof this.props.inputRef === 'function') {
      this.props.inputRef(el);
    } else {
      this.props.inputRef.current = el;
    }
  }

  // Do something with `this.buttonRef.current`

  render () {
    return <button ref={this.attachRef}>Button</button>;
  }
}

First, is this the right approach?

And if so, Typescript types say:

interface RefObject<T> {
  readonly current: T | null;
}

Which prevents us from assigning to current. Shouldn’t it not be readonly?

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:26
  • Comments:37 (2 by maintainers)

github_iconTop GitHub Comments

53reactions
volivacommented, Mar 26, 2019

This is particularly useful for hooks now, because you might have two pieces of encapsulated logic that they should work toghether.

For instance, let’s say we have two hooks:

  • useHeight(): [height: number, ref: Ref<HTMLElement>] => whenever ref mounts, it gets the height of that element, and listens to resize events that updates height.
  • useScrollY(): [scrollY: number, ref: Ref<HTMLElement>] => whenever ref mounts, it gets the current scroll position of the element, and listens to scroll events that updates the scrollY.

In this use case, we need to pass those refs to the same element, so we need a way of combining them.

14reactions
volivacommented, May 31, 2019

Just if anyone is interested, here it’s my implementation (in typescript):

/**
 * Combines many refs into one. Useful for combining many ref hooks
 */
export const useCombinedRefs = <T extends any>(...refs: Array<Ref<T>>): Ref<T> =>
    useCallback(
        (element: T) =>
            refs.forEach(ref => {
                if (!ref) {
                    return;
                }

                // Ref can have two types - a function or an object. We treat each case.
                if (typeof ref === 'function') {
                    return ref(element);
                }

                // As per https://github.com/facebook/react/issues/13029
                // it should be fine to set current this way.
                (ref as any).current = element;
            }),
        refs
    );

This is a hook that accepts any number of any kind of ref (Ref object or ref callback) and returns another ref as a callback.

Of course the amount of refs passed to this hook can’t change, otherwise useCallback will fail.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How can I use multiple refs for an array of elements with hooks?
The simplest and most effective way is to not use useRef at all. Just use a callback ref that ...
Read more >
Forwarding Refs - React
Ref forwarding is an opt-in feature that lets some components take a ref they receive, and pass it further down (in other words,...
Read more >
How to create multiple refs in React with useRef
3. Dynamically create as many refs as you want. Assume we will have 4 input elements on the page — so we use...
Read more >
Everything You Need to Know About Refs in React
In conventional JavaScript, you would tell exactly how you want your code to proceed with the onClick handler. You would select the element...
Read more >
A Guide for Refs in React - DEV Community ‍ ‍
Another way to pass multiple refs to child component: You can construct an object of Refs, and passe it as props with a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found