Dynamic Global Modal React Native

637 Views Asked by At

I'm trying to build a global dynamic modal / toast notification component that is accessible in react-native and also outside of a component context, where I can pass text and also callbacks to the buttons onClick handlers.

I tried building it with context api and hooks, but now I cannot access it from outside of a react component.

I thought about building it with redux, so I can call it from outside of react and also in components but I want the modal to be dynamic. So I would need to pass a callback function in the payload and save it to the state. But a function is non-serializeable and should not be saved to the redux store.

How would you deal with this? Are portals a thing in react-native and usable outside of react components? What other approaches are viable options here?

1

There are 1 best solutions below

2
Hamas Hassan On

There is one solution that I used to show Modal also from the outside of the React Component without using redux or context API.

First of all, render your dynamic modal at the root of your application.

   <YourModalComponent
      ref={ref => DataHandler.setYourModalComponentRef(ref)}
    />

As you can see in the above code we are taking the component ref and saving it in our DataHandler file.

Your DataHandler file code will look something like this.

let modalRef = null
    
export setYourModalComponentRef(ref) {
        modalRef = ref;
      },
    
export getYourModalComponentRef() {
        return modalRef;
      },

Now you have a reference to your component which you can call from anywhere with getYourModalComponentRef function.

Example:

 DataHandler.getYourModalComponentRef().show(
              { // any data //},
              () => {// callback function if needed //}
            );

Now the main part is how your Component knows about that show method. So here is the code example for your modal component.

import React, { useImperativeHandle, useState } from 'react';
import { Modal, Button, Text } from 'react-native';

const YourModalComponent = (props, forwardedRef) => {
  const [visible, setVisisble] = useState(false);
  const [data, setData] = useState([]);
  const [callback, setCallback] = useState({});

  useImperativeHandle(forwardedRef, () => ({
    show: (newData, cb) => {
      setData(newData);
      setCallback(cb);
      setVisisble(true);
    },
    hide: () => {
      hideModal();
    },
  }));

  const hideModal = () => {
    setVisisble?.(false);
  };

  return (
    <Modal visible={visible} onRequestClose={hideModal}>
      <Text>{data.title}</Text> // accessed the passed data.
      <Text>{data.message}</Text>
      <Button title="Done" onPress={() => callback()} />
    </Modal>
  );
};
export default React.forwardRef(YourModalComponent);

By using this approach you can use any type of modal and from anywhere in the app.

I hope this solution helps you out. Feel free to ask if you have any queries!!!