ionic-framework: bug: Nested IonRouterOutlet prevents component unmount

Bug Report

Ionic version:

5.0.1

Here is a repo with a minimal code to reproduce the bug: https://github.com/OoDeLally/ionic-nested-router-outlet-bug

Ionic info:

▶ ionic info 

Ionic:

   Ionic CLI       : 5.4.16 (/home/pascal/.nvm/versions/node/v8.16.0/lib/node_modules/ionic)
   Ionic Framework : @ionic/react 5.0.1

Utility:

   cordova-res                          : not installed
   native-run (update available: 0.3.0) : 0.2.9

System:

   NodeJS : v8.16.0 (/home/pascal/.nvm/versions/node/v8.16.0/bin/node)
   npm    : 6.4.1
   OS     : Linux 4.15


About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 8
  • Comments: 30 (2 by maintainers)

Most upvoted comments

Hello all,

I’m looking into this now, hope to have something to report on soon.

Anybody? This is a huge blocker for me

This is a huge blocker for me.

Hi All,

We have a dev release that provides better support for nested IonRouterOutlet components. There is a new prop on IonRouterOutlet that lets the router know it is a nested outlet to better perform the transition.

If your’e outlet is a nested outlet directly rendered by a Route in a parent outlet, then use the ionPage prop on the IonRouterOutlet. Here is an example:

App.tsx:

const App: React.FC = () => (
  <IonRouterOutlet>
    <Route path="/sub1" component={Sub1Outlet}  />
    <Route path="/sub2" component={Sub2Outlet} />
  </IonRouterOutlet>
);

Sub1Outlet.tsx:

const Sub1Outlet: React.FC = () =>  (
    <IonRouterOutlet ionPage>
      <Route path="/sub1" exact={true} 
        render={() => <Redirect to="/sub1/page" />} />
      <Route path="/sub1/page" component={Page1} exact={true} />
    </IonRouterOutlet>
  );

Sub2Outlet.tsx:

const Sub2Outlet: React.FC = () =>  (
    <IonRouterOutlet ionPage>
      <Route path="/sub2" exact={true} 
        render={() => <Redirect to="/sub2/page" />} />
      <Route path="/sub2/page" component={Page2} exact={true} />
    </IonRouterOutlet>
  );

If you can, could you try to install it and let us know if it fixes the issue and if you run into any others? To install it run:

npm i @ionic/react@5.3.0-dev.202006222125.df37029 @ionic/react-router@5.3.0-dev.202006222125.df37029

If all goes good this should be available in the next Ionic release.

Thanks!

It seems to me that Ionic just don’t deal with these issues.

In case of Vue framework, adding key attribute to “ion-router-outlet” resolved it for me

<ion-router-outlet id="main-content" :key="route.fullPath" ></ion-router-outlet>

I first noticed this issue with a single layer of routes (no nesting) and an apollo query with the no-cache option. Desired outcome, anytime i navigate to page X it would re-query the backend. I was surprised to see it not making the query a 2nd or more times. After days of searching git issues and changing versions of apollo/ionic etc i tried a useEffect callback function and noticed it wasn’t working which is what apollo’s useQuery uses to refetch.

All that to say i think the not unmounting components on forward and none directions is a premature optimization. What if we made this an option on the Route? <Route cache={true}/> or something? This way the dev has to opt into the optimization and isn’t surprised by it. [If enough ppl +1s this idea i can start working on a PR]

window.location

No, God, please, no 😃 Try this https://github.com/ionic-team/ionic/issues/20707#issuecomment-598806108

I found a workaround.

You can set an id to the <IonPage>. When you click the header button, the app will go back and remove your page from the DOM.

This is to force unmount the page, and because this page is no longer on the DOM it cannot execute its life cycles.

This is my helper function

export const removePageFromDOM = (pageId: string) => {
    const element = document.getElementById(pageId)
    setTimeout(()=>{
        return element && element.remove()
    }, 1000) // Give a little time to properly unmount your previous page before removing the old one
}

This is my page

   return (
        <IonPage id="PageId">
              ...
        </IonPage>
    );

This is my custom header

const Header: React.FC<Props> = ({title}) => {
    const history = useHistory();

    const handleBack = ()=>{
        history.goBack();
        removePageFromDOM("PageId")
    }

    return (
        <IonHeader>
            <IonToolbar>
                    <IonButtons slot="start">
                        <IonButton onClick={handleBack}>
                            <IonIcon slot="icon-only" ios={chevronBack} md={arrowBack}/>
                        </IonButton>
                    </IonButtons>
                <IonTitle>{title}</IonTitle>
            </IonToolbar>
        </IonHeader>
    );
};

Hope this helps

The issue continues. There is no need for nested ionrouteroutlet. The problem occurs at only one router. https://github.com/ionic-team/ionic-framework/issues/20298 https://github.com/ionic-team/ionic/issues/20844 https://github.com/ionic-team/ionic/issues/20597

It didn’t unmount the component for me. For now I will stick with routerDirection="back". Although it’s not correct, it’s working the way I need

Hi, any news of this? I’ve tried to investigate checking the source code, but it seems beyond my level of understanding.