React ForwardRef
React forwardRef

React ForwardRef

Dead Simple Chat Team

Table of Contents

This article was updated on 17 September 2024 t0 include updated diagrams and a segment on practical use cases of forward refs.

What is Forward Ref

ForwardRef() is a utility function in react that let you expose a child components DOM to a parent component with a ref

Usually the parent component passes the props and data to the child component.

But in some instances like when working with input or where components need to respond with user interactions.

The parent components needs direct access to the child components DOM, to achieve this you can use forward refs

I will explain forward ref in more details along with examples below

const CoolComponent = forwardRef(render);

Let us take an example of a form component

How does React ForwardRef work

Dead Simple Chat allows you to add chat in your React Applications using powerful JavaScript Chat API and SDK. With Dead Simple Chat you can add chat to your application in minutes.

Create a new project and Exposing a DOM node to the parent component

create a new react js project in your computer and follow along

In your app.js file write the below code

import { useRef } from 'react';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
  }

  return (
    <form>
    </form>
  );
}
react

here we are importing useRef and creating a default functional component form

in the form create a const ref and initialize the useref with null

Now create a new file named CoolInput.js

In CoolInput.js write the below code there

import { forwardRef } from 'react';

const CoolInput = forwardRef(function CoolInput(props, ref) {
  const { label, ..otherProps } = props;
  return (
    <label>
      {label}
      <input {...otherProps} ref={ref} />
    </label>
  );
});

export default MyInput;
CoolInput.js

here we are importing the forwardref from react then we are wrapping the CoolInput function in the forwardref the ref is attached to the input elements ref attribute

Forwarding Refs Through Multiple Components

Coming back to our app.js file add some additional code to it and it should look like this

import { useRef } from 'react';
import CoolInput from './input.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
  }

  return (
    <form>
      <CoolInput label="Type some text here:" ref={ref} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}
app.js file

Here we are adding a form and then we are passing the ref to the input.

Additionally we have created a button and attached its onClick to a handleClick function that focuses the on the text input when it is clicked.

Dead Simple Chat allows you to add chat in your React Applications using powerful JavaScript Chat API and SDK. With Dead Simple Chat you can add chat to your application in minutes.

Testing the application

Here is what the application looks like

application looks like

when you click on the edit button the input area comes into focus

The form component passes a ref to the CoolInput. CoolInput component then forwards that ref to the browsers input tag

As a result the form component can now control the browsers input tag and call input functions on it like focus

Forwarding refs through multiple components

You can forward the refs through multiple components as well. Let us take our example from above and refactor it to pass the refs through multiple components

Let us create a file call middle.js and there create a component called middle component

In the middle component file paste the below code

import React from 'react';
import CoolInput from './input';

const Middle = React.forwardRef(function middle(props, ref) {
  return (
    <div>
      <h2>Middle Component</h2>
      <CoolInput ref={ref} {...props} />
    </div>
  );
});

export default Middle;

Middle.js

Here we are importing react and importing CoolInput then we are wrapping our function middle inside of forwardref

Inside of our function middle we have CoolInput and we are passing our ref there to the CoolInput Component which in turns passes it to the browsers input

Let us open our App.js file and edit it and write the below code there

import { useRef } from 'react';
import Middle from './middle';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
  }

  return (
    <form>
      <Middle ref={ref} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}
app.js

In the app.js we are referencing the Middle component and not the CoolInput component and thus we are passing the ref from the Form Component to the Middle component to the CoolInput Component and from the CoolInput Component to the browsers input element

this is how you can pass the refs through multiple components

using the useImperativeHandle

Exposing an imperative handle instead of a DOM node

Sometimes you do not want to explore the whole DOM node / element to a component you just want to expose some function or api to the component

In our example above we just need the focus function of the browsers element in our parent component.

We do not need other functions the input element has like input.text etc

We can expose only the needed functions of the DOM element using an imperative handle

Let us learn more about imperative handle using an example

Let us refactor our above example to include just expose focus nad scrollInView functions of the input elements instead of the complete element

write the below code in the input.js file

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

const CoolInput = forwardRef(function CoolInput(props, ref) {
    const inputRef = useRef(null);

    useImperativeHandle(ref, ()=> {
        return {
            focus(){
                inputRef.current.focus()
            },
            scrollIntoView(){
                inputRef.current.scrollIntoView();
            }
        }
    }, []);

    return <input {...props} ref={inputRef} />;

});

export default CoolInput;
input.js

We are importing forwardRef, useRef and useImperitiveHandle from react

we are initializing the useRef with null and assigning it to a inputRef const

then we are wrapping the CoolInput in the forwardRef function then we are calling the useImperitiveHandle function with ref as the prop and returning the focus and scrollIntoView functions

we also return the input ref with the input element

useImperitiveHandle is used to customize what value is passed using the ref to the parent component

The empty array is also passed as the third argument so that the custom api is only created once in a components lifecycle

Dead Simple Chat allows you to add chat in your React Applications using powerful JavaScript Chat API and SDK. With Dead Simple Chat you can add chat to your application in minutes.

Common Pitfalls

a. Over-using refs

You should only use refs for situations where you cannot achieve the desired results using props

If you can use props instead of a ref, you should use the props

using refs increases app complexities

b. slowdown in performance

using refs causes increased re rendering of the components and slows down the application and hence they should only be used when necessary

c. Incompatibility with older versions of react

the refs are incompatible with older versions of react and hence cannot be used in older applications

d. maintenance of code and readability of code

refs cause readability and maintenance problems because they strech to multple files and you need to follow the tread and trace where this is leading

e.  Should not be used in higher order components

Higher order components should not use refs because it increase complexity and may cause hard to debug errors

refs should only be used in lower order components such as an input tag or an scroll view and should be designed to achieve a specific objective

Dead Simple Chat allows you to add chat in your React Applications using powerful JavaScript Chat API and SDK. With Dead Simple Chat you can add chat to your application in minutes.

Forward Refs using Examples

Here are a few more examples of uising refs

WriteText.js file

import React from 'react';

const WriteText = React.forwardRef((props, ref) => {
  return <input ref={ref} type="text" {...props} />;
});

export default WriteText;

App.js

import React, { useRef } from 'react';
import WriteText from './WriteText';

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

  const handleButtonClick = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <WriteText ref={inputRef} />
      <button onClick={handleButtonClick}>Elements in focus is Input</button>
    </div>
  );
}

export default App;
App.js

Here the WriteText components forwards the input element directly to the parent

Dead Simple Chat allows you to add chat in your React Applications using powerful JavaScript Chat API and SDK. With Dead Simple Chat you can add chat to your application in minutes.

Example 2 : forwarding refs to an instance of a child component

Here we are going to expose a method of the child component to the parent component

The parent component can then call the function inside of the child component


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

const Calculator = React.forwardRef((props, ref) => {
  const [count, setCount] = useState(0);

  useImperativeHandle(ref, () => ({
    add: () => {
      setCount(count => count + 1);
    }
  }));

  return <div>Number: {count}</div>;
});

export default Calculator;
Calculator.js

This is the calculator.js the child component file.

next we look at the App.js file

import React, { useRef } from 'react';
import Calculator from './Calculator';

function App() {
  const CalculatorRef = useRef();

  const handleButtonClick = () => {
    CalculatorRef.current.add();
  };

  return (
    <div>
      <Calculator ref={CalculatorRef} />
      <button onClick={handleButtonClick}>Add number</button>
    </div>
  );
}

export default App;
app.js

In the app.js we can cal the Calculator ref function Add() to add number to the count.

Thus in this way we can access the child components method from the parent component

ForwardRef Reference

forwardRef(render): You can call forwardRef(render) to let your component receive a ref and forward it to a child component

Parameters

render  the render funtion for your component. The react calls this render function with props and refs that the component received from its parent

The JSX will be return from your component. A component recieved from forwardRef can also recieve a ref prop

Return

forwardRef Returns a component that you can render in JSX

Caveats

In strict mode the react will call the render function twice. But if your render function is pure as it should be this should not affect the output of your component.

Practical Use-Cases

Accessing the DOM elements within child components, is common when working with react.

Often when you need a parent component to access a child components DOM node directly like for controlling the focus or manipulating the styles.

Passing the refs to the child component can be a challenge, this is due to the react's architecture of unidirectional data flow and encapsulation of component logic.

To help with this, react has provided us with the forwardRef API. Using this api the child components can expose their internal DOM node directly to the parent component

This mechanism is important for building reusable components that are flexible and maintainable in nature

Let us consider some real world example to better understand this

Scenario:

Let us consider a custom TextInput component, we want the parent component to control the text input field when it comes into focus, this could be in response to a user clicking it

Challenges:

  • Accessing the DOM directly: The parent component cannot directly access the DOM node of TextInput component because it is encapsulated
  • Ref forwarding: When you are passing a ref from the parent component to a child component the child component has to handle it appropriately

Solution:

We can use the React.forwardRef  the TextInput component can then forward the ref to the underlying DOM element and the parent component can then directly interact with it

Integrating with third party libraries

When you are working with react applicaitons sometimes you need to use the third party libraries for things like pre-built components and functionalities

However, you might need to wrap these components in orderto

  • Add custom styling or behaviour
  • Standardized APIs across your application
  • Or if you want ot extend the functionality of your app without changing the orignal library code

One challange arises is that how can you manage refs when wrapping the components

Refs are important for accessing child DOM elements or component instances especially when you need do things like

  • Focus on an input field
  • Trigger animations
  • Integrate with non-react libraries

By default React does not pass the refs through components unless expicitly handled

These times you can use the react.forwardRef can be useful.

Higher order components and Refs

Using the forwardRefs with HOC

Higher Order Components are functions that take a component and return a new component,

They enhance it with additional functionalities, some of the common use cases are

  • State management
  • Logging and
  • Authorization checks

However, the HOCs can interfere with the refs passing, this is because the refs are not passed as props. By default refs are attached to the HOC do not react the wrapped component

Problem:

  • Ref Blocking: When you wrap a component with HOC the refs are that you attach to the HOC does not get passed on to the  child component
  • Functional component and refs: Functional components cannot accept the refs unless you use the forwardRefs

Solution:

You can use the forwardRefs you pass the refs from the higher order components to the child components and also pass the refs to functional components using this

Conclusion

In this article we have learnt what are react refs, how to use them

I hope you liked the article

Thanks for reading