React Native Notes 34: Seamless Data Passing to React-Native-Modal
Mastering useImperativeHandle
for Dynamic Modal Content
Presenting information in a modal is as common as it is critical. But what if you need to ensure the modal content is as dynamic as the user’s journey? Passing data to the modal precisely when it’s about to make its grand entrance.
Using useState
or useRef
might seem like a logical step, yet it can tie you into knots of confusion and lifecycle complexities. Because react-native-modal
does not re-render when toggled, we need a strategy to handle the data at the right moment — just as the modal unfolds.
For those who wish to skip the why and how and jump straight into the code, check out the fully working example on GitHub:
The Strategy: useImperativeHandle
For those who are here for the journey, grab a beverage 🍻, and let’s delve into the nuances of efficient data handling with modals in React Native.
We’re going to use useImperativeHandle
hook to control the open and close functionality of the modal by passing any type of data.
import {forwardRef, useImperativeHandle, useState} from 'react';
import {StyleSheet, Text, View} from 'react-native';
import Modal from 'react-native-modal';
import {ExampleData} from '../../App';
// This is the ref interface that will be exposed to parent.
export interface ModalRef {
openModal: (data: ExampleData) => void;
}
const ModalComponent = forwardRef<ModalRef, {}>((props, ref) => {
const [isVisible, setIsVisible] = useState(false);
const [modalData, setModalData] = useState<ExampleData>();
// This function will be callable by the parent component.
const openModal = (data: ExampleData) => {
setModalData(data); // Use the data passed by parent.
setIsVisible(true);
};
// This function will be callable by the parent component.
const closeModal = () => {
setIsVisible(false);
};
// Expose the `openModal` and `closeModal` functions to parent component.
useImperativeHandle(ref, () => ({
openModal,
closeModal,
}));
return (
<Modal
style={styles.modal}
isVisible={isVisible}
onBackdropPress={closeModal}>
{modalData && (
<View style={styles.container}>
<Text>{modalData.message}</Text>
</View>
)}
</Modal>
);
});
const styles = StyleSheet.create({
modal: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
container: {
height: '50%',
width: '80%',
borderRadius: 16,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
});
export default ModalComponent;
We’re exposing the openModal
and closeModal
functions to parent component and handling the passed data inside openModal
function since we’re going to call openModal
outside of the modal with the modal’s forwarded ref.
Integrating the Modal with Parent Component
We need to forward our modal component’s ref outside so we can access our modal component’s openModal
and closeModal
functions to control the modal.
import React, {useRef} from 'react';
import {View, TouchableOpacity, StyleSheet, Text} from 'react-native';
import ModalComponent, {ModalRef} from './src/modal/ModalComponent';
export type ExampleData = {
message: string;
};
const App: React.FC = () => {
const modalRef = useRef<ModalRef>(null);
const handleOpenModal = () => {
// You can pass any data to the `openModal` function.
const dataToPass: ExampleData = {message: 'Hello from Parent!'};
modalRef.current?.openModal(dataToPass);
};
return (
<View>
<ModalComponent ref={modalRef} />
<TouchableOpacity style={styles.button} onPress={handleOpenModal}>
<Text style={styles.buttonText}>{'Open Modal'}</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
button: {
height: 45,
width: 250,
marginTop: 35,
borderRadius: 16,
backgroundColor: 'purple',
alignSelf: 'center',
alignItems: 'center',
justifyContent: 'center',
},
buttonText: {
color: '#fff',
},
});
export default App;
As you can see, we have only <ModalComponent ref={modalRef} />,
and thanks to useImperativeHandle
hook we can control the modal itself with its forwarded ref now.
// You can pass any data to the `openModal` function.
const dataToPass: ExampleData = {message: 'Hello from Parent!'};
modalRef.current?.openModal(dataToPass);
With this pattern, we can dynamically pass any data to the openModal
function, enabling the modal to refresh its content upon each invocation.
Summing Up
Using useImperativeHandle
and forwardRef
, we gain granular control over the modal's behavior, making the content dynamic and responsive to user interactions. This technique allows us to update the modal's content right before it is displayed, ensuring a smooth and reactive user experience.
This guide is a quick insight into a powerful pattern. Should you have inquiries or require further clarification, don’t hesitate to drop a comment. Happy coding!