Ionic/React app params from <Link> works in web browser, but the receiving page gets the params as "undefined" in the emulator

In the Ionic/React app, the param passed by page A using component got picked up in page B, but only when running in web browser. In the emulator the param value is “undefined”.

But If I run on a web browser first, then when running the app on emulator, the param value shows up.

The code samples are as below:

In page A:

import { Link}  from “react-router-dom”
…
<Link to={`/collection/detail/${itemid}`}> Item Id: ${itemid} </Link>
.....

In page B:

.....
  const { itemId } = useParams<Params>();
.....

In App.tsx:

<IonApp>
            <IonReactRouter>
                <IonSplitPane contentId="main">
                    
                    <Menu/>
                    <IonRouterOutlet id="main">
                      
                      ........
                        <Route exact path={"collection/list"}><PrivateRoute component={<CollectionList/>}/></Route>
                        
                        <Route exact path={"/collection/detail/:itemId"}><PrivateRoute component={<ItemDetail/>}/></Route>
                      ........
                        <FirstPage/>
                    
                    </IonRouterOutlet>
                </IonSplitPane>
            </IonReactRouter>
</IonApp>

Ionic framework should support both web and native code, therefore I am confused. Lots of thanks here for any thought.

How is the param value (itemId in page A) getting set? Is the link actually set and the param value is incorrect, or is the link not set, causing the param value to be incorrect?

Hi @ptmkenny the item Id is from a previous API call, it shows in the sending page already. For example, in that page it is render as a table with column as Item ID, and the row is aa, bb, cc, …So you can see the values (aa, bb, cc…) are there. The value is used in the Link component to go to the ItemDetail page.

At debugging, in web browser the itemId has value in the detail page. But absent in the emulator, when I debug with the Chrome devtool.

Please feel free to ask for any clarification. Thank you.

So <ItemDetail> component is getting loaded but useParams can’t see the value for itemId, even though itemId is set in the URL?

That is correct. As I debug along the break points, it goes to the ItemDetail and after the line of
const { itemId } = useParams() the itemId is still undefined. But when run in a web browser, itemId has a correct value.

This behavior is similar to this issue But I can not apply the Switch tag to Ionic/React router, as that solution implies.

The issue you linked does look similar, and if you don’t have a <Switch>, you need one. I am using basically the same structure as the linked issue in my app. <Switch> is wrapped in a suspense component because I use Tanstack Query suspense queries to load some heavy pages, but the code in the linked issue looks correct to me as well.

Here’s just the beginning of my router:

  <IonReactRouter basename={appBaseName}>
    <Suspense fallback={<FallbackLoadingPage />}>
      <Switch>
        <Route path={routes.myPath}>
          <RouteMyPath />
        </Route>

And my ionic info

Ionic:

   Ionic CLI       : 7.2.1 (/opt/homebrew/lib/node_modules/@ionic/cli)
   Ionic Framework : @ionic/react 8.7.5

Capacitor:

   Capacitor CLI      : 7.4.3
   @capacitor/android : 7.4.3
   @capacitor/core    : 7.4.3
   @capacitor/ios     : 7.4.3


These are all the latest versions, so if <Switch> is not working for you, there is probably an issue with your code.

Thank you. My environment versions are:
Ionic:

Ionic CLI : 7.2.1 (…/.nvm/versions/node/v20.17.0/lib/node_modules/@ionicionicionicionicionicionicionicionic/cli)
Ionic Fr@ionicmewo@ionicionick : @ionic/react 8.7.5

Capacitor:

Ca@capac@capacitortoracitor@capacitCL@capacit @capacitor : 7.4.3
@capacit@capacitorr/android : 7.4.3@capa@capacitor@capacitortor@capacitor/core : 7.4.3
@capacitor/ios : 7.4.3

Utility:

cordova-res : not installed globally
native-run : 2.0.1

In App.tsx: (After adding Switch tag)

import {IonApp, IonRouterOutlet, IonSplitPane, setupIonicReact} from "@ionic/react"
import {IonReactRouter} from "@ionic/react-router"
import { Route, Redirect } from "react-router-dom";
import { RouteComponentProps, Switch } from "react-router";
       ......

<IonApp>
            <IonReactRouter>
                <IonSplitPane contentId="main">
                    
                    <Menu/>
                    <IonRouterOutlet id="main">
                      <Switch>
                      ........
                        <Route exact path={"collection/list"}><PrivateRoute component={<CollectionList/>}/></Route>
                        
                        <Route exact path={"/collection/detail/:itemId"}><PrivateRoute component={<ItemDetail/>}/></Route>
                      ........
                        <FirstPage/>
                       </Switch>
                    </IonRouterOutlet>
                </IonSplitPane>
            </IonReactRouter>
</IonApp>

After applying Switch tag, the emulator has blank screen.

When I enter the path and parameter directly in the Chrome Devtools, the parameter shows up and show expected detail. So it does look like a router issue. But I got stuck still because the Switch tag causes a white screen. I wondered if it is compatible. But you can have it without a problem, apparently.

Thank you in advance for any thought!

What happens if you remove all the stuff that isn’t part of the router, like <IonSplitPane> from the router so you just have IonReactRouter -> IonRouterOutlet -> Switch`?

I dont’ use IonSplitPane, but the documentation suggests it should go in an IonPage, not in the router directly. For Ionic React Router, every router child MUST be an IonPage.

I removed <IonSplitPane> and still saw the blank screen. Now the App.tsx has this:

import {IonApp, IonRouterOutlet, IonSplitPane, setupIonicReact} from "@ionic/react"
import {IonReactRouter} from "@ionic/react-router"
import { Route, Redirect } from "react-router-dom";
import { RouteComponentProps, Switch } from "react-router";
       ......

<IonApp>
            <IonReactRouter>
                    
                    <Menu/>
                    <IonRouterOutlet id="main">
                      <Switch>
                      ........
                        <Route exact path={"collection/list"}><PrivateRoute component={<CollectionList/>}/></Route>
                        
                        <Route exact path={"/collection/detail/:itemId"}><PrivateRoute component={<ItemDetail/>}/></Route>
                      ........
                        <FirstPage/>
                      </Switch>
                    </IonRouterOutlet>
     
            </IonReactRouter>
</IonApp>

Try making the child component of a <Route> an <IonPage>. Your wrapper component may be incorrectly set up. If you’re still having trouble, I would check one of the Ionic demo apps that already has routing set up, and if you still can’t figure it out, try creating a full repro that you can share. There’s really not enough code here to determine what is going wrong.

I will try to make an example project here, thank you.

By the way, more information here:

If I run another way:

Step 1. Run with the web browser first,

Result: Data shows up in the detail page(which is because the params has value)

Step 2. Then run with the emulator after switching VITE_SERVER_URL

The data shows up in the detail page(which is because the params has value)