ionic-framework
ionic-framework copied to clipboard
bug: React fallback route causes flicker transition when routing between pages
Prerequisites
- [X] I have read the Contributing Guidelines.
- [X] I agree to follow the Code of Conduct.
- [X] I have searched for existing issues that already report this problem, without success.
Ionic Framework Version
- [X] v4.x
- [X] v5.x
- [X] v6.x
Current Behavior
Summary:
Navigating to a random page right after implementing a default or a guarded route or a fallback route (following the method suggested in docs also https://ionicframework.com/docs/react/navigation#fallback-route) and then moving back and forth in the app leads to flickering/black glitch. Reloading the same page seems to correct this issue.
Context:
Hey there, We decided to go with ionic react for our patient application and we are nearly done with that. While setting page boundaries. I’ve decided to redirect the user based on a context value and prevent from falling into any unmatched route.
Here is how I declared that:
return <QueryClientProvider client={queryClient}>
<IonApp>
<IonReactRouter>
<IonSplitPane contentId="main">
{isLoggedIn && <Menu />}
<IonRouterOutlet id="main">
<Route path="/home" render={() => isLoggedIn ? <Home /> : <Redirect to="/login" />} exact={true} />
<Route path="/payment-history" render={() => isLoggedIn ? <PaymentHistory /> : <Redirect to="/login" />} exact={true} />
<Route path="/renewal" render={() => isLoggedIn ? <Packages /> : <Redirect to="/login" />} exact={true} />
<Route path="/session-result/:type" render={() => isLoggedIn ? <SessionResult /> : <Redirect to="/login" />} exact={true} />
<Route path="/treatment-plan" render={() => isLoggedIn ? <TreatmentPlan /> : <Redirect to="/login" />} exact={true} />
<Route path="/profile" render={() => isLoggedIn ? <Profile /> : <Redirect to="/login" />} exact={true} />
<Route path="/cancellation-policy" render={() => isLoggedIn ? <CancellationPolicy /> : <Redirect to="/login" />} exact={true} />
<Route path="/terms-and-conditions" render={() => isLoggedIn ? <TermsAndConditions /> : <Redirect to="/login" />} exact={true} />
<Route path="/help" render={() => isLoggedIn ? <Help /> : <Redirect to="/login" />} exact={true} />
<Route path="/notifications" render={() => isLoggedIn ? <Notifications /> : <Redirect to="/login" />} exact={true} />
<Route path="/getting-started" render={() => isLoggedIn ? <GettingStarted /> : <Redirect to="/login" />} exact={true} />
<Route path="/progress-report" render={() => isLoggedIn ? <Progress /> : <Redirect to="/login" />} exact={true} />
<Route path="/policies" render={() => isLoggedIn ? <Policies /> : <Redirect to="/login" />} exact={true} />
<Route path="/login" render={() => !isLoggedIn ? <Authentication /> : <Redirect to="/home" />} exact={true} />
<Route render={() => !isLoggedIn ? <Redirect to={'/login'} /> : <Redirect to={'/home'} />} />
{/* <Redirect to={ !isLoggedIn ? '/login' : '/home' } /> */}
{/* { MountedRoutes } */}
</IonRouterOutlet>
</IonSplitPane>
</IonReactRouter>
</IonApp>
{ process.env.REACT_APP_ENV_STAGE === 'dev' && <ReactQueryDevtools initialIsOpen={false} />}
</QueryClientProvider>;
Navigation is working fine but there is an issue with how it’s animating, it ended up giving strange flickering while moving from one page to other page. One thing which I observed is when I refresh the page, flickering goes away and everything works as expected.
Here is the package.json:
{
"name": "patient-app",
"version": "0.0.2",
"private": true,
"dependencies": {
"@capacitor/android": "3.3.4",
"@capacitor/app": "1.0.7",
"@capacitor/clipboard": "^1.0.6",
"@capacitor/core": "3.3.3",
"@capacitor/haptics": "1.1.3",
"@capacitor/keyboard": "1.2.0",
"@capacitor/splash-screen": "^1.2.0",
"@capacitor/status-bar": "^1.0.6",
"@dotmind/react-use-pwa": "^1.0.4",
"@frogress/line": "^1.1.0",
"@ionic/react": "^6.0.0",
"@ionic/react-router": "^6.0.0",
"@testing-library/jest-dom": "^5.11.9",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^12.6.3",
"@types/jest": "^26.0.20",
"@types/node": "^12.19.15",
"@types/react": "^16.14.3",
"@types/react-dom": "^16.9.10",
"@types/react-router": "^5.1.11",
"@types/react-router-dom": "^5.1.7",
"chart.js": "^3.7.0",
"classnames": "^2.3.1",
"contentful": "^9.1.6",
"date-fns": "^2.28.0",
"firebase": "^9.6.1",
"framer-motion": "^4.1.17",
"html-react-parser": "^1.4.5",
"ionicons": "^5.4.0",
"lodash": "^4.17.21",
"react": "^17.0.1",
"react-chartjs-2": "^4.0.0",
"react-dom": "^17.0.1",
"react-icons": "^4.3.1",
"react-lines-ellipsis": "^0.15.0",
"react-onesignal": "^2.0.2",
"react-otp-input": "^2.4.0",
"react-phone-input-2": "^2.14.0",
"react-query": "^3.34.12",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.2",
"styled-components": "^5.3.3",
"typescript": "^4.1.3",
"web-vitals": "^0.2.4",
"workbox-background-sync": "^5.1.4",
"workbox-broadcast-update": "^5.1.4",
"workbox-cacheable-response": "^5.1.4",
"workbox-core": "^5.1.4",
"workbox-expiration": "^5.1.4",
"workbox-google-analytics": "^5.1.4",
"workbox-navigation-preload": "^5.1.4",
"workbox-precaching": "^5.1.4",
"workbox-range-requests": "^5.1.4",
"workbox-routing": "^5.1.4",
"workbox-strategies": "^5.1.4",
"workbox-streams": "^5.1.4"
}
I’m not sure what’s going wrong here. I tried all the other solutions mentioned on other posts as well but non of them working.
Expected Behavior
The default route should land on the target page and would not produce any flickering or black glitch while moving in the app
Steps to Reproduce
Please follow the git https://github.com/ashishbairwa/router-bug-ionic for the walkthrough.
Alternatively:
- Create a new ionic react app with template as sidemenu.
- Add two pages in the app
- Add the routes for them and place a default route following this https://ionicframework.com/docs/react/navigation#fallback-route
- Implement buttons to move back and forth across page.
- Moving to any page right after entering an undefined route in the URL would lead to glitch
Code Reproduction URL
https://github.com/ashishbairwa/router-bug-ionic
Ionic Info
Ionic:
Ionic CLI : 6.18.1 (C:\Users\Ashish Bairwa\AppData\Roaming\npm\node_modules@ionic\cli) Ionic Framework : @ionic/react 6.0.5
Capacitor:
Capacitor CLI : 3.3.3 @capacitor/android : 3.3.4 @capacitor/core : 3.3.3 @capacitor/ios : not installed
Utility:
cordova-res : not installed globally native-run : 1.5.0
System:
NodeJS : v16.13.1 (C:\Program Files\nodejs\node.exe) npm : 6.14.14 OS : Windows 10
Additional Information
Video proofs: https://youtu.be/kuEK9mkZx84 https://youtu.be/wg8vt6HvBlY
Linked issue in forum: https://forum.ionicframework.com/t/flickering-black-glitch-while-redirecting-to-some-other-page/220096/8
Hello @ashishbairwa thanks for moving this conversation into Github from our discord conversation.
To help narrow the reproduction information, can you confirm if this accurately describes the problem as you understand it (based on your reproduction app)?
- Start at
/home
. - Click "Move to my name" button to navigate to
/ashish
. - Click the "Move to" button to navigate between pages.
- See that the transitions are smooth between pages .
- In the browser address bar, enter an invalid URL, such as:
/abc
(press enter/navigate). - You are navigated back to
/home
. - Click "Move to" button to navigate.
- Continue to click "Move to" buttons.
- See that the transitions are flickering/animating incorrectly.
Hello @ashishbairwa thanks for moving this conversation into Github from our discord conversation.
To help narrow the reproduction information, can you confirm if this accurately describes the problem as you understand it (based on your reproduction app)?
- Start at
/home
.- Click "Move to my name" button to navigate to
/ashish
.- Click the "Move to" button to navigate between pages.
- See that the transitions are smooth between pages .
- In the browser address bar, enter an invalid URL, such as:
/abc
(press enter/navigate).- You are navigated back to
/home
.- Click "Move to" button to navigate.
- Continue to click "Move to" buttons.
- See that the transitions are flickering/animating incorrectly.
Yes, idea is to use the fallback route once. Right after that animation seems to break.
Awesome, thanks! I've updated the title and see the same behavior on my end. We will capture this as a bug and prioritize in an upcoming sprint.
Any progress on that?
I have cloned and updated all the dependencies to check if it's resolved but i can still see flickering without even doing any thing. @sean-perkins
It's been an year now. Do you guys have any update regarding this? @sean-perkins @liamdebeasi
@ashish-yourphysio this is still an open issue in our backlog. The team has worked on many issues in the past year. Issues are prioritized by a variety of metrics. For community issues we weigh them on potential impact and upvotes (interest).
The code is open source and freely available to provide assistance that can lead to this issue being resolved sooner. Additional debugging insight into the problematic code or a fix to the issue would be appreciated by both the team and the community.
I understand this issue may be extremely critical to your application, but we are small team that tries to solve the largest sum problems across Ionic Framework (web components, Angular, React and Vue), Ionic docs (documentation and live examples) and the Stencil Framework Wrappers for DX for frameworks consuming our web components.
We have improvements for routing in design, but it is unclear if they would have an immediate impact to this specific issue, without identifying the root cause to the transition flickering with the fallback route defined.
I can confirm that the problem still exists. If the page starts and there is a redirect that occurs than the transitions are flickering, here is a stackblitz - you can see in App.tsx that there are comments, regarding the redirects. Only "open" redirect causes flickering (btw only if you start the app from "/", if you refresh at "/customer/tabs/home" then everything works fine) The commented Redirects together gets the same result but no flickering occurs, even if you start the page from "/".
https://stackblitz.com/edit/aexcxb?file=src%2FApp.tsx (to try the page refreshes you can open the demo in full page) One last thing, the demo is not complicated so you'll see only drawback in performance but when there are more elements it's flickering in a bad way.
I can confirm this is still existing in Ionic 7. Any news?
Okay i think i was able to fix it. Previously this is how we use router guards:
<IonRouterOutlet animated>
{COMMON_ROUTES.map((item) => (
<AuthenticatedRoute
key={item.path}
path={item.path}
component={item.component}
exact
/>
))}
</IonRouterOutlet>
Simply put, we use custom component and either return the component or return a redirect depending on the authentication. Turns out flickering only happens on navigation if IonRoute is not a direct child of the IonRouterOutlet
so what i did instead is something like:
<IonRoute
path={LOGIN}
render={(props) => unauthenticatedRender(props, baseUser, SignIn)}
exact={true}
/>
where unauthenticatedRender:
import isNull from "lodash/isNull";
import { Redirect } from "react-router-dom";
import { LazyExoticComponent, Suspense } from "react";
import { BaseUser } from "../../../Common/models/user";
import { COMPLETE_SIGN_UP, DASHBOARD } from "../../constants/routes";
export const unauthenticatedRender = (
props: any,
user: BaseUser | undefined | null,
C: (() => JSX.Element) | LazyExoticComponent<() => JSX.Element>
) => {
const path = props.location.pathname;
if (user !== undefined && !isNull(user)) {
if (!user.completedSignUp) {
return <Redirect to={COMPLETE_SIGN_UP} />;
}
return <Redirect to={DASHBOARD} />;
} else {
return (
<Suspense>
<C {...props} />
</Suspense>
);
}
};
This solved it for me! hope this can help
Okay i think i was able to fix it. Previously this is how we use router guards:
<IonRouterOutlet animated> {COMMON_ROUTES.map((item) => ( <AuthenticatedRoute key={item.path} path={item.path} component={item.component} exact /> ))} </IonRouterOutlet>
Simply put, we use custom component and either return the component or return a redirect depending on the authentication. Turns out flickering only happens on navigation if IonRoute is not a direct child of the IonRouterOutlet
so what i did instead is something like:
<IonRoute path={LOGIN} render={(props) => unauthenticatedRender(props, baseUser, SignIn)} exact={true} />
where unauthenticatedRender:
import isNull from "lodash/isNull"; import { Redirect } from "react-router-dom"; import { LazyExoticComponent, Suspense } from "react"; import { BaseUser } from "../../../Common/models/user"; import { COMPLETE_SIGN_UP, DASHBOARD } from "../../constants/routes"; export const unauthenticatedRender = ( props: any, user: BaseUser | undefined | null, C: (() => JSX.Element) | LazyExoticComponent<() => JSX.Element> ) => { const path = props.location.pathname; if (user !== undefined && !isNull(user)) { if (!user.completedSignUp) { return <Redirect to={COMPLETE_SIGN_UP} />; } return <Redirect to={DASHBOARD} />; } else { return ( <Suspense> <C {...props} /> </Suspense> ); } };
This solved it for me! hope this can help
You are using "exact" which is not a fallback route and this is why you don't have the exact problem, the issue still persists:(