DEV Community

Gervais Yao Amoah
Gervais Yao Amoah

Posted on

Understanding React’s forwardRef Once and For All

React is an extremely powerful JavaScript library, and its flexibility is one of the reasons for its widespread adoption. As developers, it’s essential to understand the concepts that allow us to write cleaner and more reusable code. One such concept in React is forwardRef, a higher-order component that enables passing refs through components to a DOM node or another component. In this article, we will take a deep dive into understanding React’s forwardRef, its purpose, how it works, and how to use it effectively in real-world applications.

What is forwardRef in React?

At its core, forwardRef is a React API that allows us to forward a ref from a parent component to a child component. React refs are references to DOM elements or class components, which can be useful when you need to access or interact with these elements directly.

However, when passing refs to functional components, React doesn’t automatically forward refs because they don’t have an internal instance like class components do. This is where forwardRef comes into play. By using forwardRef, you can manually forward a ref through a functional component to a DOM element or a class component in its tree.

Why Use forwardRef?

The purpose of using forwardRef is simple — it allows components to expose their underlying DOM nodes or instances to parent components, enabling better interaction with lower-level elements. For example, you may have a custom button component, but you still want the parent component to be able to trigger focus or measure the size of the button, all through the ref.

Without forwardRef, the ref passed to the button would be ignored since the button component itself doesn’t manage or forward the ref.

How Does forwardRef Work?

The forwardRef API is a function that takes two arguments:

  1. A functional component that accepts props and the ref.
  2. A ref object that gets passed down to the component.

In essence, forwardRef allows the functional component to pass the ref it receives from the parent component to one of its children or to a DOM element. It ensures that the ref is not swallowed, as would happen if it were handled by a normal functional component.

Basic Syntax of forwardRef

Here’s the basic syntax of forwardRef:

const MyComponent = React.forwardRef((props, ref) => {
  return <div ref={ref}>Hello, {props.name}!</div>;
});
Enter fullscreen mode Exit fullscreen mode

In this example:

  • props: These are the props passed down from the parent component.
  • ref: This is the reference to the DOM element, which can be used by the parent component.

How to Use forwardRef with Functional Components?

Let’s walk through an example of how to use forwardRef with a functional component.

import React, { useRef } from 'react';

// Define a functional component
const Button = React.forwardRef((props, ref) => {
  return <button ref={ref}>{props.label}</button>;
});

const App = () => {
  const buttonRef = useRef();

  const focusButton = () => {
    buttonRef.current.focus(); // Focus on the button element directly
  };

  return (
    <div>
      <Button ref={buttonRef} label="Click Me" />
      <button onClick={focusButton}>Focus on the above Button</button>
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

In this example:

  • The Button component uses forwardRef to pass down the ref to the <button> DOM element.
  • The parent App component uses the useRef hook to manage the ref and later triggers the focus method.

Using forwardRef in Class Components

Though forwardRef is most commonly used with functional components, it can also be used in class components. If you are working with a class component and need to forward a ref, the syntax remains similar.

class MyComponent extends React.Component {
  render() {
    return <input ref={this.props.forwardedRef} />;
  }
}

const ForwardedMyComponent = React.forwardRef((props, ref) => {
  return <MyComponent {...props} forwardedRef={ref} />;
});
Enter fullscreen mode Exit fullscreen mode

Here, ForwardedMyComponent will receive the ref and pass it down to the MyComponent class component.

Common Use Cases for forwardRef

Let’s explore some of the most common use cases where forwardRef can be extremely beneficial:

1. Accessing DOM Elements Directly

When you want to access the underlying DOM element of a component (like setting focus, measuring size, or performing animations), you can forward a ref to that DOM element.

2. Integrating with Third-Party Libraries

When working with third-party libraries, such as UI component libraries or custom animations, you may need to forward a ref to interact with those components directly.

3. Wrapping Third-Party Components

If you are wrapping a third-party component and need to expose a ref to the DOM element or instance, forwardRef is the solution. This allows you to interact with the child component while keeping your wrapper component clean.

4. Optimizing Performance in Higher-Order Components (HOCs)

In complex applications, HOCs can wrap and enhance other components. With forwardRef, you can pass the ref through higher-order components to the underlying child components without breaking the ref flow.

Best Practices for Using forwardRef

1. Only Use When Necessary

While forwardRef is a powerful tool, it should be used sparingly. Ref forwarding can make components less reusable and harder to test, so only use it when it’s absolutely necessary.

2. Avoid Using Refs for State Management

Using refs for managing state is not a recommended pattern. forwardRef should primarily be used for accessing DOM elements or components, not for managing or storing data.

3. Combine with useImperativeHandle

When you need to expose certain methods from a child component to the parent, useImperativeHandle combined with forwardRef can be used to expose a controlled API. This ensures that the parent can invoke specific methods on the child component directly.

Here’s an example:

import React, { useRef, useImperativeHandle } from 'react';

const CustomInput = React.forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
    clear: () => {
      inputRef.current.value = '';
    },
  }));

  return <input ref={inputRef} />;
});

const App = () => {
  const inputRef = useRef();

  const focusInput = () => {
    inputRef.current.focus(); // Focus on the custom input field
  };

  const clearInput = () => {
    inputRef.current.clear(); // Clear the input field
  };

  return (
    <div>
      <CustomInput ref={inputRef} />
      <button onClick={focusInput}>Focus Input</button>
      <button onClick={clearInput}>Clear Input</button>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

In this case, the parent App can directly call methods like focus or clear on the child component, exposing a controlled API through useImperativeHandle.

Conclusion

React’s forwardRef is a crucial tool for passing refs through functional components and enabling parent-child component communication via direct access to DOM elements. By using forwardRef, developers can ensure more flexible and reusable components while maintaining clean code. It’s essential to use this API judiciously and understand its power and implications to make your React applications more dynamic and performant.

Top comments (0)