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

bug: React Router stops updating page on back button or IonBackButton usage

Open philjones88 opened this issue 3 years ago • 6 comments
trafficstars

Prerequisites

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

philjones88 avatar Aug 30 '22 15:08 philjones88

Removed lazy loading from our app and it didn't fix the issue. Guess it's another React 18 + Ionic React Router issue?

philjones88 avatar Sep 06 '22 13:09 philjones88

@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 avatar Sep 13 '22 21:09 sean-perkins

@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

philjones88 avatar Sep 13 '22 22:09 philjones88

@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

philjones88 avatar Sep 14 '22 07:09 philjones88

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...

philjones88 avatar Sep 14 '22 10:09 philjones88

@sean-perkins managed to fix it in my app:

  • removing lazy loading pages
  • swapping i18next react to useSuspense to false (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.

philjones88 avatar Sep 16 '22 12:09 philjones88

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!

sean-perkins avatar Oct 18 '22 20:10 sean-perkins

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.

ionitron-bot[bot] avatar Nov 17 '22 20:11 ionitron-bot[bot]