Call Child Function from Parent in Reactjs using useRef
Asked Answered
M

2

5

The Code is written using React Functional components.

Upon clicking button in parent, the function showAlert should be fired. That is the requirement.

Currently in the parent component childRef.current is not able to call showAlert() function. I get a typescript error

Property 'showAlert' does not exist on type 'ForwardRefExoticComponent<RefAttributes<unknown>>'

Parent Functional component Code

import React, { forwardRef, useRef, useImperativeHandle } from 'react';
import Child from './Child';
export default function App() {
  const childRef = useRef<typeof Child>(Child);
  return (
    <div className="container">

      <Child ref={childRef} />
      <button
        onClick={() => { childRef.current.showAlert() }}
      >
        Call Function
            </button>
      
    </div>
  )
}

Child Functional component

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

const Child = forwardRef((props, ref) => {
    useImperativeHandle(
        ref,
        () => ({
             showAlert() {
                alert("Child Function Called")
                console.log('hello world')
            }
        }),
    )
    return (
        <div>Child Component</div>
    )
})

export default Child
Mallorymallow answered 25/2, 2021 at 6:14 Comment(2)
You're almost there but there are some typescript types that you need to fill in on the Child. I can write an answer.Galluses
@LindaPaiste could you please write the answer. It would be really helpfulMallorymallow
G
21

You've got this almost right, but typeof Child is not giving you an accurate type because the Child component itself is not typed strictly enough. It's getting inferred as forwardRef<unknown, {}>. We need to specificity the type of the forwarded ref in order for this to work.

We can define an interface for the ref that we want:

interface CanShowAlert {
  showAlert(): void;
}

We set the two generics on the forwardRef function for Child. CanShowAlert is the ref type and {} is the props type:

const Child = forwardRef<CanShowAlert, {}>((props, ref) => {

We use the same generic on the useRef:

const childRef = useRef<CanShowAlert>(null);

You get an error with your initial value useRef<CanShowAlert>(Child) because the ref is for an instance of the component, but you are passing in the component function itself. Instead we use null as the initial value.

The current property of the ref will either be a component instance or null, so we need to make sure that it's not null before we call the showAlert function. We can use the optional chaining operator ?. for that.

childRef.current?.showAlert()

Complete code:

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

interface CanShowAlert {
  showAlert(): void;
}

export default function App() {
  const childRef = useRef<CanShowAlert>(null);
  return (
    <div className="container">

      <Child ref={childRef} />
      <button
        onClick={() => { childRef.current?.showAlert() }}
      >
        Call Function
            </button>
      
    </div>
  )
}


const Child = forwardRef<CanShowAlert, {}>((props, ref) => {
    useImperativeHandle(
        ref,
        () => ({
             showAlert() {
                alert("Child Function Called")
                console.log('hello world')
            }
        }),
    )
    return (
        <div>Child Component</div>
    )
})
Galluses answered 25/2, 2021 at 6:50 Comment(1)
OMG, this is great! Exactly what I've been looking forDichlamydeous
Q
0

Try this way

useImperativeHandle(
        ref,
        () => ({
             showAlert: () => { // like this here
                alert("Child Function Called")
                console.log('hello world')
            }
        }),
)
Quita answered 25/2, 2021 at 6:21 Comment(1)
It says Property 'showAlert' does not exist on type 'ForwardRefExoticComponent<RefAttributes<unknown>>' Is the Declaration of useRef wrong here ?Mallorymallow

© 2022 - 2024 — McMap. All rights reserved.