DEV Community

Mario
Mario

Posted on • Originally published at mariokandut.com on

Forwarding refs to components

Refs provide a way to access DOM nodes (or React elements) created in the render method, but why would you forward a reference?

Forwarding refs

Ref forwarding in React means, that a reference through a component is automatically passed to one of its children. Typically, this is not necessary for most components, but sometimes, it is very useful. Let's find out why.

Forwarding refs to DOM components

Forwarding refs can be useful in reusable component libraries. Let's consider an AwesomeButton component, that renders the native button DOM element.

functon AwesomeButton(props) {
  return(
    <button>{props.children}</button>
  )
}
Enter fullscreen mode Exit fullscreen mode

React components hide their implementation details, including their rendered output. This means that other components using the AwesomeButton, will usually not obtain a ref to the inner DOM element. This encapsulation is good, because it prevents components from relying heavily on each other's DOM structure. A high level of encapsulation is desirable on application-level, it can be unpractical for highly reusable leaf components (think of the React tree). These leaf components like AwesomeButton are used like native DOM elements, like a button, and managing focus, selection or animations require access to their DOM nodes.

Ref-forwarding lets some components take a ref they receive, and pass it further down (forward it) to a child. In the example below the ref passed to AwesomeButton is forwarded down to the DOM button, which gives components using the AwesomeButton component access to the button DOM node, just like they would use a DOM button directly.

const AwesomeButton = React.forwardRef((props, ref) => (
  <button ref={ref}>{props.children}</button>
));

const ref = React.useRef();
<AwesomeButton ref={ref}>Click it</AwesomeButton>;
Enter fullscreen mode Exit fullscreen mode

After attaching the ref, ref.current will point to the <button> DOM element.

Forwarding refs in higher-order components

Higher-Order Components or HOCs can benefit from this ref forwarding technique. Let's have a look at a HOC example, which logs component props to the console.

function logProps(WrappedComponent) {
  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('old props:', prevProps);
      console.log('new props:', this.props);
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  }

  return LogProps;
}
Enter fullscreen mode Exit fullscreen mode

The logProps HOC passes all props through the wrapped components and, it doesn't affect the rendered output. Let's apply this on the AwesomeButton.

class AwesomeButton extends React.Component {
  //...
}
export default logProps(AwesomeButton);
Enter fullscreen mode Exit fullscreen mode

Then we import the AwesomeButton and apply a reference.

import AwesomeButton from './AwesomeButton';
//...
const ref = createRef();
//...
<AwesomeButton
  label="click it"
  handleClick={handleClick}
  ref={ref}
/>;
Enter fullscreen mode Exit fullscreen mode

There is one thing to consider, ref is not a prop. The reference passed to AwesomeButton, which is now a Higher-Order-Component, will not be passed down, because ref is not a prop. Instead, the reference will be attached to the HOC logProps.

To avoid this we can explicitly forward refs to the inner AwesomeButton component using forwardRef. The React.forwardRef API receives props and ref parameters and returns a React.node.

function logProps(Component) {
  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('old props:', prevProps);
      console.log('new props:', this.props);
    }

    render() {
      const { forwardedRef, ...rest } = this.props;

      // Assign the custom prop "forwardedRef" as a ref
      return <Component ref={forwardedRef} {...rest} />;
    }
  }

  // The second parameter in forwardRef can be used as a normal prop.
  return React.forwardRef((props, ref) => {
    return <LogProps {...props} forwardedRef={ref} />;
  });
}
Enter fullscreen mode Exit fullscreen mode

TL;DR

  • In React ref and key are handled differently.
  • The React.forwardRef API receives props and ref parameters and returns a React.node.
  • In HOC, it's important to know that ref is not a prop and will not be automatically forwarded with other props. React.forwardRef has to be used.

Thanks for reading and if you have any questions , use the comment function or send me a message @mariokandut. If you want to know more about React, have a look at these React Tutorials.

References (and Big thanks):

React Docs - Forwarding Refs,React Docs - Refs,Bits and Pieces,LogRocket

Top comments (1)

Collapse
 
projektorius96 profile image
LG

@mario 's content is always 100+ karma points !