HomeHow to call child component method with forwardRef and useImperativeHandle in React

How to call child component method with forwardRef and useImperativeHandle in React

Published: 6/12/2023

Calling a child method is a common architecture problem that occurs in a React app. You can pass individual properties to child components, you can alter the component state inside of the same component, but how to actually call another component's method?

There's a way to do that by using a combination of forwardRef with useImperativeHandle.

What exactly are those functions for? Let's quote the documentation:

  • forwardRef lets your component expose a DOM node to parent component with a ref.
  • useImperativeHandle customizes the instance value that is exposed to parent components when using ref. As always, imperative code using refs should be avoided in most cases.

So, we need to do both things - first, wrap a component with a forwardRef, then useImperativeHandle to fake the ref the component returns. I'm going to throw together a simple Button component:

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

let buttonIndex = 0;

const ChildButton = forwardRef((props, ref) => {
  ++buttonIndex;

  const index = buttonIndex;

  useImperativeHandle(ref, () => ({
    showMe() {
      let div = document.createElement('div');
      div.innerText = index;
      document.getElementById('result').appendChild(div);
    }
  }));

  return <button style={{ backgroundColor: '#4594ff', border: 'none', fontSize: '16px', padding: '10px', cursor: 'pointer' }}>{props.text}</button>
})

With this, the component is ready to receive a ref and will return the object we provide as a second parameter in useImperativeHandle. Now, the main component just needs to provide a ref, and it will be able to call the child methods through the ref variable:

const App = function() {
  const ref1 = useRef();
  const ref2 = useRef();
  const ref3 = useRef();

  return <div>
    <div style={{ gap: 8, display: 'flex' }}>
      <span onClick={() => { ref1.current.showMe(); }}>
        <ChildButton text="Button 1" ref={ref1} />
      </span>
      <span onClick={() => { ref2.current.showMe(); }}>
        <ChildButton text="Button 2" ref={ref2} />
      </span>
      <span onClick={() => { ref3.current.showMe(); }}>
        <ChildButton text="Button 3" ref={ref3} />
      </span>
    </div>
    <div id="result" style={{ fontSize: '16px' }}></div>
  </div>
}

And here's the result!

About Code with Node.js

This is a personal blog and reference point of a Node.js developer.

I write and explain how different Node and JavaScript aspects work, as well as research popular and cool packages, and of course fail time to time.