ionic-framework icon indicating copy to clipboard operation
ionic-framework copied to clipboard

bug: Ionic React app with Tabs breaks tab navigation when opening a modal on a nested tab page

Open hansvn opened this issue 2 years ago • 5 comments

Prequisites

Ionic Framework Version

  • [ ] v4.x
  • [X] v5.x
  • [ ] v6.x

Current Behavior

When creating an Ionic React application that has a modal in a nested tab page, the tab navigation will break after opening the modal.

The Application in the provided repository has three tabs: Tab 1, Tab 2 and Tab 3. Tab 3 has a nested page (path /tab3/page1) and on that page there is a simple <IonModal>. When you open (and close) the modal on the nested page, the navigation to Tab 1 will break (Page 1 remains visible - app location is updated to /tab1). Oddly, when you navigate to Tab 2 with the tab button, navigation for that tab still works.

Expected Behavior

The App should show the content of Tab 1 page when tapped on the tab bar button.

Steps to Reproduce

  • Create a new Ionic React app with tabs
  • Add a nested page in Tab 3 (with entry in App.tsx router outlet <Route path="/tab3/page1" component={Page1} />)
  • Add a modal in the nested page
  • Run the app, navigate to Tab 3
  • Go to the nested page in Tab 3
  • Open (and close) the modal in the nested page
  • Navigate to Tab 1
  • See Bug (the nested page remains visible)

Code Reproduction URL

https://github.com/hansvn/Ionic-React-tab-navigation-with-modal-bug

Ionic Info

Ionic:

Ionic CLI : 6.17.0 (/usr/local/lib/node_modules/@ionic/cli) Ionic Framework : @ionic/react 5.7.0

Capacitor:

Capacitor CLI : 3.2.0 @capacitor/android : not installed @capacitor/core : 3.2.0 @capacitor/ios : not installed

Utility:

cordova-res : 0.15.3 native-run : 1.4.0

System:

NodeJS : v12.14.0 (/usr/local/bin/node) npm : 7.6.0 OS : macOS Big Sur

Additional Information

I suspect the router doesn't hide the ion-page Dom element. The nested page has the can-go-back class on the element, but there is no ion-page-hidden added to that element when navigating to the first tab.

hansvn avatar Sep 01 '21 21:09 hansvn

I have the same problem, did you find any solution for this?

BetoGlez avatar Sep 03 '21 16:09 BetoGlez

@BetoGlez Unfortunately I haven't been able to find a solution. I tried conditionally rendering the modal, but once it has been opened the navigation breaks. So that didn't do the trick either. Probably going to refactor the modals into pages as a quick fix for now.

hansvn avatar Sep 10 '21 16:09 hansvn

@hansvn I've found that this issue doesn't happen if you use the modal in the hook way useIonModal() instead of the component way <IonModal>, hope this helps you as a quick fix.

BetoGlez avatar Sep 13 '21 12:09 BetoGlez

@BetoGlez That works indeed. One catch is that using that hook makes the modal loose it's references to a redux store and apollo client (if your app has one). So passing the store and client - with useStore() and useApolloClient() hooks - to the modal properties and wrapping the modal inside providers mimics the same behavior as using the <IonModal> component.

P.S. For anyone landing on this page with the same issue, I updated my code to use a different hook than useIonModal:

// useConnectedModal.ts
import { useApolloClient } from '@apollo/client';
import { useIonModal } from '@ionic/react';
import { ReactComponentOrElement } from '@ionic/react/dist/types/hooks/useOverlay';
import { useStore } from 'react-redux';

const useConnectedModal = (component: ReactComponentOrElement, componentProps?: any) => {
  return useIonModal(component, {
    store: useStore(),
    client: useApolloClient(),
    ...componentProps,
  });
};

export default useConnectedModal;

with the modal component (Functional Component)

const YOUR_MODAL_COMPONENT: React.FC = ({ store, client, ...any_additional_modal_props }) => {
  return (
    <Provider store={store}>
      <ApolloProvider client={client}>
        // The Actual Component elements
      </ApolloProvider>
    </Provider>
  );
};

and using it with

const [presentModal, hideModal] = useConnectedModal(YOUR_MODAL_COMPONENT, { ...any_additional_modal_props });

hansvn avatar Sep 13 '21 17:09 hansvn

@hansvn Thanks for the workaround. I had the same issue but with the queryClient in React Query, so I'm definitely going to do a variation of this for now to provide that to my modals.

Am I wrong in thinking that this is also a bug though? It was brought up in #23516 and @liamdebeasi verified that this is unexpected behavior that was resolved in f3e492c. However, like you I am still seeing overlays rendered outside of the context of the React app on Ionic v6.2.2.

Happy to create a new issue if that would be helpful.

Edit: I've discovered that this issue is due to the OverlayManager being a direct child of IonApp so my issue was just that any providers inside IonApp aren't available to the modal

SeanBarker182 avatar Sep 14 '22 15:09 SeanBarker182