Page transition with black glitch

Hi there,

We’re working on an app in Ionic/React and we have a glitch when transitioning from a page to another. There is a brief black screen appearing.

On the iOS it is more visible. It looks like there is an intermediary black page between the current page and the target page.

Any help would be appreciated. I have seen some occurrences but they are from 4 years ago and the idea was to make the background transparent… but it doesn’t fix the problem.

Can you show some code? Ideally a Minimal, Reproducible Example.

Hi @Mirkonasato,

Thanks for your answer. I am quite new to this so I need a bit of time to go through the link you sent about the minimal reproducible example :slight_smile:

Hi @Mirkonasato,

I’m still figuring out how to be able to create one of these minimal reproducible examples…

However, after working on that, I changed the following in my routing:

  • items went from /{tab: (dashboard}/newsfeed/:id to /newsfeed/:id and suddenly, no more animation bug in the browser simulation.

I have however tested in Xcode and the bug is still present.

0828D3CD-698E-406F-A875-2B84D62A12F4

You don’t have to follow that link to the letter, but the point is that it’s pretty much impossible for other people to know why your app is behaving in a certain way without seeing the code.

@mirkonasato

Below is the routing code which works in the browser simulation (i’ve simplified it):

import React from 'react';
import {
  IonApp,
  IonTabs,
  IonRouterOutlet,
  IonTabBar,
  IonTabButton,
  IonIcon,
  IonLabel,
} from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
import { Route, Redirect } from 'react-router';
import DashboardScreen from '../DashboardScreen';
import NewsDetailsScreen from '../NewsDetailsScreen';
import ShiftListScreen from '../ShiftListScreen';
import ShiftDetailsScreen from '../ShiftDetailsScreen';
import { home, today } from 'ionicons/icons';
import { useTranslation } from 'react-i18next';

const App: React.FC = () => {
  const { t } = useTranslation();
  return (
    <IonApp>
      <IonReactRouter>
        <IonTabs>
          <IonRouterOutlet>
            <Route path="/:tab(dashboard)" component={DashboardScreen} />
            <Route path="/:tab(upcoming)" component={ShiftListScreen} />
            <Route path="/newsfeed/:id" component={NewsDetailsScreen} />
            <Route path="/shifts/:id" component={ShiftDetailsScreen} />
            <Route render={() => <Redirect to="/dashboard" />} />
          </IonRouterOutlet>
          <IonTabBar slot="bottom">
            <IonTabButton tab="dashboard" href="/dashboard">
              <IonIcon icon={home} />
              <IonLabel>{t('tabs.home')}</IonLabel>
            </IonTabButton>
            <IonTabButton tab="upcoming" href="/upcoming">
              <IonIcon icon={today} />
              <IonLabel>{t('tabs.upcoming')}</IonLabel>
            </IonTabButton>
          </IonTabBar>
        </IonTabs>
      </IonReactRouter>
    </IonApp>
  );
};

export default App;

Here is the code that creates the black screen (in the browser simulation):

import React from 'react';
import {
  IonApp,
  IonTabs,
  IonRouterOutlet,
  IonTabBar,
  IonTabButton,
  IonIcon,
  IonLabel,
} from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
import { Route, Redirect } from 'react-router';
import DashboardScreen from '../DashboardScreen';
import NewsDetailsScreen from '../NewsDetailsScreen';
import ShiftListScreen from '../ShiftListScreen';
import ShiftDetailsScreen from '../ShiftDetailsScreen';
import { home, today } from 'ionicons/icons';
import { useTranslation } from 'react-i18next';

const App: React.FC = () => {
  const { t } = useTranslation();
  return (
    <IonApp>
      <IonReactRouter>
        <IonTabs>
          <IonRouterOutlet>
            <Route path="/:tab(dashboard)" component={DashboardScreen} />
            <Route path="/:tab(upcoming)" component={ShiftListScreen} />
            <Route path="/:tab(dashboard)/newsfeed/:id" component={NewsDetailsScreen} />
            <Route path="/:tab(dashboard)/shifts/:id" component={ShiftDetailsScreen} />
            <Route path="/:tab(upcoming)/shifts/:id" component={ShiftDetailsScreen} />
            <Route render={() => <Redirect to="/dashboard" />} />
          </IonRouterOutlet>
          <IonTabBar slot="bottom">
            <IonTabButton tab="dashboard" href="/dashboard">
              <IonIcon icon={home} />
              <IonLabel>{t('tabs.home')}</IonLabel>
            </IonTabButton>
            <IonTabButton tab="upcoming" href="/upcoming">
              <IonIcon icon={today} />
              <IonLabel>{t('tabs.upcoming')}</IonLabel>
            </IonTabButton>
          </IonTabBar>
        </IonTabs>
      </IonReactRouter>
    </IonApp>
  );
};

export default App;

The difference between the 2 is the added /:tab(tabname) in the route of the sub elements shifts and newsfeed.

I don’t know if that’s what’s causing you problems, but you seem to assume that IonRouterOutlet will only render the first Route that matches the requested path. That’s not how it works. If multiple routes match they will all be rendered.

So with

          <IonRouterOutlet>
            <Route path="/:tab(dashboard)" component={DashboardScreen} />
            <Route path="/:tab(upcoming)" component={ShiftListScreen} />
            <Route path="/:tab(dashboard)/newsfeed/:id" component={NewsDetailsScreen} />
            <Route path="/:tab(dashboard)/shifts/:id" component={ShiftDetailsScreen} />
            <Route path="/:tab(upcoming)/shifts/:id" component={ShiftDetailsScreen} />
            <Route render={() => <Redirect to="/dashboard" />} />
          </IonRouterOutlet>

if you request e.g. /dashboard/newsfeed/1 that will match your first, third, and last route.

Make sure there are no overlaps between your paths by using the exact prop, and remove the last route that will always match.

Actually, the way IonRouterOutlet works seem to have changed in v5.3.0. What I said above applies to v5.2.3 and earlier. Since v5.3.0 it seems to render the last matching route in the list if there are multiple matches. In any case it’s a good idea to use exact.

1 Like

Hi @mirkonasato

Thanks for this. It did solve my issue of having the glitch in the browser when using the tab route (second code).

It does not fix it when I run the app on my iPhone however, but this may be linked to a different problem. One thing at a time :slight_smile:

Hey it’s me again…

After a small break, I did a new change…
I replaced

<Route render={() => <Redirect to="/dashboard" />} />

which @mirkonasato suggested to delete with

<Route path="/" render={() => <Redirect to="/dashboard" />} exact={true} />

And now I have no problems on iOS with the transitions. I figured it would be helpful for someone at some point. Thank you @mirkonasato for your precious help.

Glad you got it working. You can actually simplify that last line if you want to:

<Redirect exact from="/" to="/dashboard" />

For some reason this didn’t work and broke the navigation. But I’m ok with the other solution :slight_smile: