A Child component method can call the parent component method using React Refs.
We need three hooks for functional components. They are useRef, forwardRef, and useImperativeHandle.
Example with Typescript and functional components
- The first step is to create a ref in the parent component.
const childRef = useRef() as React.MutableRefObject<RefHandler>
- Then we pass that ref down to the child component.
<Input name="name" ref={childRef}/>
- To receive ref as a prop, the child component must be wrapped in React.forwardRef method. The forwardRef method accepts a function as arguments.
That function the forwardRef accepts (the child component) must receive props and ref as arguments. That is how forwardRef binds ref to the child component.
const Input = forwardRef<RefHandler,InputProps>((props, ref) => {
- In the child component, the useImperativeHandle controls the exposure of the component properties to its parent through ref. The useImperativeHandle accepts the ref from the parent and an object of properties to expose.
useImperativeHandle(ref, () => ({
childFunction : (val: string): void => {
alert(val)
}
}))
Here is the complete code snippet in Typescript.
import React, { forwardRef, useImperativeHandle, useRef, useState } from "react"
interface InputProps {
name: string
}
type RefHandler = {
childFunction: (val: string) => void
}
export const Form = () => {
const childRef = useRef() as React.MutableRefObject<RefHandler>;
const callChildFunction = (val: string) => {
childRef.current.childFunction(val);
}
return (
<>
<Input name="name" ref={childRef}/><button onClick={() => callChildFunction("From Parent")}>Ok</button>
</>
)
}
const Input = forwardRef<RefHandler,InputProps>((props, ref) => {
useImperativeHandle(ref, () => ({
childFunction : (val: string): void => {
alert(val)
}
}))
return(
<div><input name={props.name}/></div>
)
})
Example with Javascript and functional components
If your project is in Javascript, here is the same version with Javascript.
import { forwardRef, useImperativeHandle, useRef } from "react"
export const Form = () => {
const childRef = useRef()
const callChildFunction = (val) => {
childRef.current.childFunction(val);
}
return (
<>
<Input name="name" ref={childRef}/><button onClick={() => callChildFunction("From Parent")}>Ok</button>
</>
)
}
const Input = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
childFunction : (val) => {
alert(val)
}
}))
return(
<div><input name={props.name}/></div>
)
})
Example with Javascript and class components
For those who use class based components, here is the class component version of the same. If you use a React version > 16.8, consider upgrading your React component to a functional component.
import React, { Component } from "react";
export class Form extends Component{
constructor(props) {
super(props);
this.childRef = React.createRef()
}
callChildFunction = (val) => {
this.childRef?.current?.childFunction(val);
}
render() {
return(
<>
<Input name="name" ref={this.childRef}/><button onClick={() => this.callChildFunction("From Parent")}>Ok</button>
</>
)
}
}
export class Input extends Component{
childFunction = (val) => {
alert(val)
}
render() {
return(
<div><input name={this.props.name}/></div>
)
}
}