AI-Generated [Thanks DALL-E]

React Native Notes 34: Seamless Data Passing to React-Native-Modal

Kuray Ogun
FreakyCoder Software Blog
3 min readNov 24, 2023

--

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 openModalfunction 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!

--

--