Last updated: Apr 7, 2024
Reading timeยท3 min
useImperativeHandle
To call a child's function from a parent component in React:
Child
component in a forwardRef
.useImperativeHandle
hook in the child to add a function to the
Child
.childRef.current.childFunction()
.import {forwardRef, useImperativeHandle, useRef} from 'react'; const Child = forwardRef((props, ref) => { useImperativeHandle(ref, () => ({ childFunction1() { console.log('child function 1 called'); }, childFunction2() { console.log('child function 2 called'); }, })); return ( <div> <h2>child content</h2> </div> ); }); export default function Parent() { const childRef = useRef(null); const handleClick = () => { childRef.current.childFunction1(); childRef.current.childFunction2(); }; return ( <div> <Child ref={childRef} /> <h2>parent content</h2> <button onClick={handleClick}>Call child functions</button> </div> ); }
We used a forwardRef to forward
a ref
from the Parent
component to the Child
.
forwardRef
method accepts a function that takes the props
and a ref
as parameters.const Child = forwardRef((props, ref) => { useImperativeHandle(ref, () => ({ childFunction1() { console.log('child function 1 called'); }, childFunction2() { console.log('child function 2 called'); }, })); return ( <div> <h2>child content</h2> </div> ); });
The function we pass to forwardRef
should return a React node.
We need to forward the ref
to the Child
so we can use the
useImperativeHandle
hook to customize the Child's instance value that is exposed to the Parent
component when using a ref
.
useImperativeHandle(ref, () => ({ childFunction1() { console.log('child function 1 called'); }, childFunction2() { console.log('child function 2 called'); }, }));
The Parent
component that renders <Child ref={childRef} />
will be able to
call childFunction1
as childRef.current.childFunction1()
.
Alternatively, you can use a more indirect approach.
useEffect
This is a three-step process:
count
state variable in the Parent component.count
variable to the dependencies of the useEffect
hook in the
Child.count
in the Parent to rerun the child's useEffect
.import {useEffect, useState} from 'react'; const Child = ({count}) => { useEffect(() => { const childFunction1 = () => { console.log('child function 1 called'); }; const childFunction2 = () => { console.log('child function 2 called'); }; // ๐๏ธ don't run on the initial render if (count !== 0) { childFunction1(); childFunction2(); } }, [count]); return ( <div> <h2>child content</h2> </div> ); }; export default function Parent() { const [count, setCount] = useState(0); const handleClick = () => { setCount(current => current + 1); }; return ( <div> <Child count={count} /> <h2>parent content</h2> <button onClick={handleClick}>Call child functions</button> </div> ); }
The Parent
component declares a count
state variable and passes it as a prop
to the Child
.
We added the count
variable to the dependencies of the
useEffect hook, so every time it
changes, the function we passed to useEffect
is going to run.
useEffect(() => { const childFunction1 = () => { console.log('child function 1 called'); }; const childFunction2 = () => { console.log('child function 2 called'); }; // ๐๏ธ don't run on initial render if (count !== 0) { childFunction1(); childFunction2(); } }, [count]);
The Child
component declares and calls 2 functions in the useEffect
hook.
The Parent
can run the logic in the Child's useEffect
hook by changing the
count
state variable.
count
is not equal to 0
before calling the functions in useEffect
.if (count !== 0) { childFunction1(); childFunction2(); }
The useEffect
hook is run when the component mounts and every time one of its
dependencies changes.
If you don't want to run the logic on mount check that the count
variable is
not equal to 0
before calling the functions.
Conversely, if you want to run the Child function from the Parent component when the Child mounts, remove the conditional.
const Child = ({count}) => { useEffect(() => { const childFunction1 = () => { console.log('child function 1 called'); }; const childFunction2 = () => { console.log('child function 2 called'); }; // ๐๏ธ Call function on Mount as well childFunction1(); childFunction2(); }, [count]); return ( <div> <h2>child content</h2> </div> ); };
The code sample calls the Child function from the Parent component when the components mount and every time the button is clicked.
We simply removed the if
statement that checks if the count
state variable
is equal to 0
.