ionic-framework
ionic-framework copied to clipboard
bug: React Router stops updating page on back button or IonBackButton usage
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
- [ ] v4.x
- [ ] v5.x
- [X] v6.x
- [ ] Nightly
Current Behavior
In a complex app, the IonBackButton component or the browsers own back button stops working. The URL updates but the pages contents do not.
I suspect it's down the lazy loading of the pages.
Expected Behavior
Page navigation works.
Steps to Reproduce
This is a code sandbox of the issue.
https://codesandbox.io/s/ionic-router-back-button-issue-eqw77o?file=/src/app.tsx
Click "Navigate". The page now shows "Hello test page 1".
Click "Go to Page 2". The page now shows "Hello test page 2".
Click the browser back or the IonBackButton component.
URL updates but the page doesn't
Code Reproduction URL
https://codesandbox.io/s/ionic-router-back-button-issue-eqw77o?file=/src/app.tsx
Ionic Info
See code sandbox. v6.2.4
Additional Information
No response
Removed lazy loading from our app and it didn't fix the issue. Guess it's another React 18 + Ionic React Router issue?
@philjones88 can you explain the usage behind:
const TestPage1 = lazy(() => import("./pages/TestPage1"));
const TestPage2 = lazy(() => import("./pages/TestPage2"));
If I replace that with standard imports:
import TestPage1 from "./pages/TestPage1";
import TestPage2 from "./pages/TestPage2";
back navigation appears to be functional: https://codesandbox.io/s/ionic-router-back-button-issue-forked-f92n7y?file=/src/app.tsx
Outside of the broken back navigation behavior in your reproduction, I also see odd flickering/re-animations of the page components, which I also believe is tied to the lazy usage (does not reproduce in my forked version).
@sean-perkins I'll try removing the lazy loading.
I was following:
https://ionic.io/enterprise-guide/react#lazy-loading
That points to:
https://reactjs.org/docs/code-splitting.html#route-based-code-splitting
@sean-perkins I've removed lazy and swapped from component on the <Route /> to render also as I noticed this as a difference to the codesandbox you sent.
I still get the URL and component getting out of sync and having to refresh the page.
I'm using Vite and React but I don't think that's the issue as I've removed lots of Vite features like chunking and tried production builds (not the Vite dev server) and the issue still happens.
I'll try and replicate it more.
I do notice this warning in Firefox developer tools when it breaks in my app:
Warning: Hash history go(n) causes a full page reload in this browser
Ok I implemented a basic version of IonBackButton to figure out what's going wrong. It seems to be when you do router.goBack() after checking router.canGoBack():
i.e. this breaks in my app in the same ways a IonBackButton:
const handleBackButton = () => {
logger.debug({ routeInfo: router.routeInfo, routeCanGoBack: router.canGoBack() }, 'handleBackButton');
if (router.canGoBack()) {
logger.debug({}, 'router can go back');
router.goBack();
} else {
logger.debug({}, 'router can NOT go back');
router.push('/home');
}
};
But if I change it to always force a push like:
const handleBackButton = () => {
logger.debug({ routeInfo: router.routeInfo, routeCanGoBack: router.canGoBack() }, 'handleBackButton');
if (router.canGoBack()) {
logger.debug({}, 'router can go back');
router.push('/home'); // <--- THIS FIXES IT! Always force a new push
} else {
logger.debug({}, 'router can NOT go back');
router.push('/home');
}
};
This works. Obviously the browser button is still broken as it's trying to go backwards I'm guessing.
The output of route info + canGoBack() is:
{
"routeInfo": {
"id": "3",
"routeAction": "push",
"routeDirection": "forward",
"lastPathname": "/home",
"pathname": "/spaces/89/manage",
"search": "",
"params": {},
"pushedByRoute": "/home"
},
"routeCanGoBack": true
}
Which indicates the state is right. So more investigation to do on my end. I cannot see anything special I'm doing versus the codesandbox...
@sean-perkins managed to fix it in my app:
- removing
lazyloading pages - swapping i18next react to
useSuspensetofalse(see https://react.i18next.com/latest/i18next-instance )
Resolves the issue.
So I guess the issue is handling of suspense inside Ionic React Router?
I could produce another sample with i18next react in it but you'd see the same behaviour as the original code sandbox where I lazy load the pages.
Thanks for the follow-up + additional details!
Ionic's React routing integration does not currently support the use of lazy and likely the handling of suspense as a result. The components must be mounted in the DOM when the navigation event occurs, so that the page transitions can correctly append the styling to animate views in/out of the visible viewport.
I am going to close out this issue, as you have resolved your issue and this is currently not a feature we support or plan to support (without a significant overhaul to Ionic's routing paradigms).
Thanks!
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.