How to call a React Child Function
Last update: 2023-10-31If you want to call a function of a child component from a parent component in React, you can use the useImperativeHandle
hook.
Let’s say we have a simple Listing
component that renders a random todo item from the JSONPlaceholder API.
import { View, Text, StyleSheet } from 'react-native';
import React, { useEffect, useState } from 'react';
type Listing = {
userId: number;
id: number;
title: string;
completed: boolean;
};
const Listing = () => {
const [data, setData] = useState<Listing>();
const loadData = async () => {
const id = Math.floor(Math.random() * 200) + 1;
const data = await fetch(`https://jsonplaceholder.typicode.com/todos/${id}`);
const json = await data.json();
setData(json);
};
useEffect(() => {
loadData();
}, []);
return (
<View style={styles.container}>
{data ? (
<Text style={{ fontSize: 20, color: '#fff' }}>{data.title}</Text>
) : (
<Text style={{ fontSize: 20, color: '#fff' }}>Loading...</Text>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: '#101353',
alignItems: 'center',
padding: 20,
margin: 20
}
});
export default Listing;
Now we want to call the loadData
function from the parent component - but how?
The easiest way is to use the useImperativeHandle
hook. It allows you to expose certain functions to the parent component.
To use it, we need to wrap our component in a forwardRef
call and pass the ref to the useImperativeHandle
hook.
import { View, Text, StyleSheet } from 'react-native';
import React, { useEffect, useState } from 'react';
import { forwardRef, useImperativeHandle } from 'react';
type Listing = {
userId: number;
id: number;
title: string;
completed: boolean;
};
interface Props {}
// Define the ref type
export type ListingRef = {
refresh: () => void;
};
// Wrap the component in a forwardRef call
const ListingGood = forwardRef<ListingRef, Props>((props, ref) => {
const [data, setData] = useState<Listing>();
const fetchData = async () => {
...
};
// Pass the ref to the useImperativeHandle hook
useImperativeHandle(ref, () => ({
refresh: () => {
fetchData();
}
}));
return (
...
);
});
const styles = StyleSheet.create({
container: {
backgroundColor: '#ff00ff',
alignItems: 'center',
padding: 20
}
});
export default ListingGood;
Within the useImperativeHandle
hook we can then define the functions that we want to expose to the parent component.
Now our parent component only needs to create a ref and pass it to the child component:
import { View, Button } from 'react-native';
import React, { useRef, useState } from 'react';
import ListingGood, { ListingRef } from '../components/ListingGood';
const Page = () => {
// Create the ref
const ref = useRef<ListingRef>(null);
// Use the ref
const updateMyChild = () => {
ref.current?.refresh();
};
return (
<View>
<Button onPress={updateMyChild} title="Update child component" />
{/* Add the ref */}
<ListingGood ref={ref} />
</View>
);
};
export default Page;
Check out the useImperativeHandle docs for more information as well!