简体   繁体   中英

Best practice for managing multiple modals in React Native

I have a screen and I need to show multiple modals in it. For example, if some request was failed then I want to show an error modal, if some request was successful then I want to show a success modal.

I currently do it as following which I think is bad practice:

...

export default function SomeSampleScreen(props) {
  const [errorModalVisible, setErrorModalVisible] = useState(false);
  const [errorMessage, setErrorMessage] = useState('');
  const [successModalVisible, setSuccessModalVisible] = useState(false);
  const [successMessage, setSuccessMessage] = useState('');

  function showError(message) {
    setErrorMessage(message);
    setErrorModalVisible(true);
  }

  function showSuccess(message) {
    setSuccessMessage(message);
    setSuccessModalVisible(true);
  }

  return (
    <>
      <ErrorModal
        visible={errorModalVisible}
        onClose={() => {
          setErrorModalVisible(false);
        }}>
        {errorMessage}
      </ErrorModal>
      <SuccessModal
        visible={successModalVisible}
        onClose={() => {
          setSuccessModalVisible(false);
        }}>
        {successMessage}
      </SuccessModal>
      <View>
        ...
      </View>
    </>
  );
}

You could just condense it into one object:

export default function SomeSampleScreen(props) {
  const [modalState, setModalState] = useState({state: ''});

  function showError(message) {
    setModalState({state: "error", message});
  }

  function showSuccess(message) {
    setModalState({state: "success", message});
  }

  return (
    <>
      <ErrorModal
        visible={modalState.state === "error"}
        onClose={() => {
          setModalState({state: ''});
        }}>
        {modalState.message}
      </ErrorModal>
      <SuccessModal
        visible={modalState.state === "success"}
        onClose={() => {
          setModalState(false);
        }}>
        {modalState.message}
      </SuccessModal>
      <View>
        ...
      </View>
    </>
  );
}

UDPATE After clarifying what the actual question is, here is a good way to do it. Create a Context:

const ModalContext = React.createContext({status: "", message: ""});

Add the context and the modals somewhere up in your tree:

constructor(props) {
    super(props);

    this.setModal = (modalState) => {
      this.setState(state => ({...state, ...modalState}));
    };
    this.state = {
      status: "",
      message: "",
      setModal: this.setModal,
    };
  }
return <ModalContext.Provider value={this.state.modalState}>
        <RestOfApp />
        <Modals/>
      </ModalContext.Provider>

The Modals would be similar to what you postet:

export default function SomeSampleScreen(props) {
  const modalState = useContext(ModalContext);

  function showError(message) {
    modalState.setModal({state: "error", message});
  }

  function showSuccess(message) {
    modalState.setModal({state: "success", message});
  }

  return (
    <>
      <ErrorModal
        visible={modalState.state === "error"}
        onClose={() => {
          modalState.setModal({state: ''});
        }}>
        {modalState.message}
      </ErrorModal>
      <SuccessModal
        visible={modalState.state === "success"}
        onClose={() => {
          modalState.setModal(false);
        }}>
        {modalState.message}
      </SuccessModal>
      <View>
        ...
      </View>
    </>
  );
}

You can use a conditional render to return different data on the same modal . Like this:

export default function SomeSampleScreen(props) {
  const [ModalVisible, setModalVisible] = useState(false);
  const [errorMessage, setErrorMessage] = useState(false);
  const [successMessage, setSuccessMessage] = useState(false);

  function showError(message) {
    setErrorMessage(message);
    setModalVisible(true);
  }

  function showSuccess(message) {
    setSuccessMessage(message);
    setModalVisible(true);
  }

  return (
    <>
      <Modal
        visible={ModalVisible}
        onClose={() => {
          setSuccessModalVisible(false);
          setSuccessMessage(false);
          setErrorMessage(false);
        }}>

        {errorMessage && (
          {errorMessage}
        )}

        { successMessage && (
          {successMessage}
        )}

      </Modal>
      <View>
        ...
      </View>
    </>
  );
}

What about it?

export default function SomeSampleScreen(props) {
  const modalInitialState = {
    type: null,
    message: null
  }
  const [modal, setModal] = useState(modalInitialState)

  function handleModal(type, message){
    setModalState({ type, message });
  }

  return (
    <>
      <ErrorModal
        visible={modal.type === 'ERROR' || false}
        onClose={() => {
          setModal(modalInitialState)
        }}>
        {modal.message}
      </ErrorModal>
      <SuccessModal
        visible={modal.type === 'SUCCESS' || false}
        onClose={() => {
          setModal(modalInitialState)
        }}>
        {modal.mensage}
      </SuccessModal>
      <View>
        ...
      </View>
    </>
  );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM