Skip to content

bug: Route match params not readable in lifecycle hooks in Ionic React #21594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
JanMisker opened this issue Jun 21, 2020 · 22 comments
Open

bug: Route match params not readable in lifecycle hooks in Ionic React #21594

JanMisker opened this issue Jun 21, 2020 · 22 comments
Labels
package: react @ionic/react package type: bug a confirmed bug report

Comments

@JanMisker
Copy link

It seems that the route match params do not get updated in the Ionic-React lifecycle hooks.

Ionic version:
[ ] 4.x
[x] 5.x.
@ionic/react: 5.2.2

Current behavior:
When a route is visited again, Ionic reuses the existing page.
This is a bit different from how React does it, but as described in the docs there are handy lifecycle hooks available to help with it.

However the route match params don't seem to update.

Expected behavior:
I would expect that the match params are updated.

Steps to reproduce:

Some pseudo-code to show the issue:

  <IonApp>
     <IonReactRouter>
       <IonRouterOutlet>
              <Route path="/home" component={Home} exact />
              <Route path="/game/:id" component={GamePage} exact />
        </IonRouterOutlet>
      </IonReactRouter>
    </IonApp>

interface GameProps
  extends RouteComponentProps<{
    id: string
  }> {}

const GamePage: React.FC<GameProps> = ({ match }) => {

useIonViewDidEnter(() => {
    console.log('useIonViewDidEnter ', match.params.id) // always the initial id
})
useEffect(() =>
    console.log('useEffect', match.params.id) // always the current id
})
return <IonPage><IonContent>{ match.params.id }</IonContent></IonPage>

In another part of the app:

history.push('/game/10');

and later

history.push('/game/11');

But

console.log('useIonViewDidEnter ', match.params.id) // always the initial id

keeps outputting 10 (the first)

Related code:
If needed I can create a sample project.

Ionic info:


Ionic:

   Ionic CLI       : 6.10.1
   Ionic Framework : @ionic/react 5.2.2

Capacitor:

   Capacitor CLI   : 2.2.0
   @capacitor/core : 2.2.0

Utility:

   cordova-res (update available: 0.15.0) : 0.14.1
   native-run                             : 1.0.0

System:

   NodeJS : v14.3.0
   npm    : 6.14.5
   OS     : macOS Catalina


@ionitron-bot ionitron-bot bot added the triage label Jun 21, 2020
@liamdebeasi liamdebeasi added the ionitron: needs reproduction a code reproduction is needed from the issue author label Jun 22, 2020
@ionitron-bot
Copy link

ionitron-bot bot commented Jun 22, 2020

Thanks for the issue! This issue has been labeled as needs reproduction. This label is added to issues that need a code reproduction.

Please provide a reproduction with the minimum amount of code required to reproduce the issue. Without a reliable code reproduction, it is unlikely we will be able to resolve the issue, leading to it being closed.

For a guide on how to create a good reproduction, see our Contributing Guide.

@ionitron-bot ionitron-bot bot removed the triage label Jun 22, 2020
@JanMisker
Copy link
Author

See this repository for a minimal example, check Detail.tsx and the console.logs in there
https://github.com/JanMisker/routeParamsBug

@elylucas
Copy link
Contributor

Hi @JanMisker,

Thanks for the repo. I just gave it a try and wasn't seeing the issue. Here is what I did:

After loading, I hit the Push 10 button, and went into the details page. The console showed:

useEffect 10
Detail.tsx:29 mounting useEffect 10
Detail.tsx:26 useEffect 10
Detail.tsx:23 useIonViewDidEnter  10

I hit the back button, updated the text field to 101, and hit the Push 101 button, when it went to the details page the console showed:

useEffect 101
Detail.tsx:29 mounting useEffect 101
Detail.tsx:26 useEffect 101
Detail.tsx:23 useIonViewDidEnter  101

From what I gathered, the bug you were saying was that the ionViewDidEnter was reporting the id was still "10" correct? Let me know if I'm missing something.

Thanks
2020-06-23_11-32-44 (1)

@JanMisker
Copy link
Author

You're right, I didn't notice that the back button seems to work ok.
However when you use the Home again link and then back to the detail it does go wrong, see my screen recording. I use the Home again Link on 11, then on 12 it goes wrong.
You also see the view is not mounted again, because there is no 'mounting useEffect 12' on the console log.

This is exactly the situation for which I would use the Ionic lifecycle hooks: Ionic keeps the view mounted, but I do want to know when it is being presented again, with up-to-date info on the parameters. The lifecycle hook documentation also specifies that it can happen like that.

For instance, componentDidMount fires the first time a page is displayed, but if you navigate away from the page Ionic might keep the page around in the DOM, and a subsequent visit to the page might not call componentDidMount again. This scenario is the main reason the Ionic lifecycle methods exist, to still give you a way to call logic when views enter and exit when the native framework's events might not fire.
from the docs

movie

@elylucas
Copy link
Contributor

@JanMisker Yep, see it now. Will take a look, thanks!

@elylucas
Copy link
Contributor

Hi @JanMisker,

Found this issue, you need to pass the param to useIonViewWillEnter in the dependencies list much like useEffect:

useIonViewDidEnter(() => {
    console.log("useIonViewDidEnter ", match.params.id); // always the initial id
  }, [match.params.id]);

Give that a try and let us know.

And sorry, I don't think thats documented, so we will get that updated.

@tottt
Copy link

tottt commented Jun 24, 2020

I have the same exact issue.
Unfortunatly adding the match.params to the dependencies does not fix this.
Something I found out: the history part of the RouteComponentProps is correct when you click again whereas the match and the location parts are wrong

@JanMisker
Copy link
Author

Thanks @elylucas that indeed fixed it!

@tottt check out my reproduction repository, maybe your case is different somewhere? https://github.com/JanMisker/routeParamsBug

@JanMisker
Copy link
Author

@elylucas come to think of it... doesn't the requirement to add a dependency array defy the usefulness of those lifecycle hooks?

@tottt
Copy link

tottt commented Jun 24, 2020

My case is quite similar to your example.
Main difference beeing that instead of linking to home I'm using a Tab navigation.

@elylucas
Copy link
Contributor

@JanMisker

The function still gets called for each enter/leave, but it only updates the value of the variables captured in the closure that are listed in the deps array.

@elylucas
Copy link
Contributor

@tott could you put together a demo repo?

@tottt
Copy link

tottt commented Jun 24, 2020

I have also created a demo repo: https://bitbucket.org/dodosch/routebugdemo
To reproduce

  1. click an the 1st link in the content
  2. Navigate "back" using the tab
  3. click on 2nd link -> Content from 1st link is shown

When you use the back button it works fine. Interestingly when you repeat step 2 and 3 it works again until you got to step 1 - then it breaks again.

@elylucas
Copy link
Contributor

@tott,

K, I see it and will take a look. In the meantime, I think you could replace the lifecycle hook with a useEffect hook to get the right param in.

@liamdebeasi liamdebeasi added triage and removed ionitron: needs reproduction a code reproduction is needed from the issue author labels Jul 7, 2020
@KrisVanHoye
Copy link

KrisVanHoye commented Feb 3, 2021

Ionic react, lifecycle hooks do not work correctly when routing with params is used!

Example:
http://localhost:8100/dashboard/1
=> useIonViewWillEnter is called for key = 1
=> useIonViewDidLeave is called for key =1

http://localhost:8100/dashboard/2
=> useIonViewWillEnter is called for key = 2
=> useIonViewDidLeave is called for key = 2

But useIonViewWillLeave and useIonViewDidLeave are never called!
Same behavior for child custom hooks, no WillLeave or DidLeave is called.
useEffect clean-up function is also not called.

Did not yet find a workaround for this!

@avalanche1
Copy link

Can we raise the priority for this bug? It's been a year with no fix - and it's a serious issue - Ionic lifecycle hooks not working as expected - what's the point of having them then?..

@kaloczikvn
Copy link

Hi @JanMisker,

Found this issue, you need to pass the param to useIonViewWillEnter in the dependencies list much like useEffect:

useIonViewDidEnter(() => {
    console.log("useIonViewDidEnter ", match.params.id); // always the initial id
  }, [match.params.id]);

Give that a try and let us know.

And sorry, I don't think thats documented, so we will get that updated.

Still no mention of this in the documentation plus I'm still stuck with this issue.

@hansvn
Copy link

hansvn commented Oct 15, 2021

@kaloczikvn can you try this:

const getId = useCallback(() => {
  return match.params.id;
}, [match.params]);

useIonViewDidEnter(() => {
    console.log("useIonViewDidEnter ", getId());
});

I've come across this bug a couple of times, and my understanding is that useIonViewDidEnter falls outside of the scope of the Functional Component. Calling a method inside the scope should return the correct id (not too sure if you'll actually need the callback, I'm writing this from the top of my head but this should be the most robust solution at this point).

@strarsis
Copy link

@hansvn: How can I use this inside a React Context? I can also move that context inside the Router components, if this is needed. But a React Context doesn't have useIonViewDidEnter support, or does it?

@hansvn
Copy link

hansvn commented Mar 18, 2022

@hansvn: How can I use this inside a React Context? I can also move that context inside the Router components, if this is needed. But a React Context doesn't have useIonViewDidEnter support, or does it?

What I've learned meanwhile is that you can pass some props to the second argument of the useIonViewDidEnter hook (it's not referenced in the docs). This acts much like the useCallback hook. You could try this to bind it to the context:

useIonViewDidEnter(() => {
    ...
}, []);

@strarsis
Copy link

strarsis commented Mar 18, 2022

@hansvn: Yes, useIonViewDidEnter is intended to be used for this - however - I noticed that it is also invoked when the page/route is currently not shown in the app! I found no way getting around this issue.
Currently I am using the properties of the RouteComponentProps prop passed down by the Ionic React Router to a view/page component:

interface ViewCategoryProps
  extends RouteComponentProps<{
    category: string;
  }> { }
const ViewCategory: React.FC<ViewCategoryProps> = ({ match }) => {
  const categorySlug = match.params.category;

For triggering something when a page is visited (e.g. "Order sending" page), I currently use the useHistory hook with push:

	onClick={() => {
		orderCtx.sendOrder();
		history.push({
			pathname: '/send',
		});
	}}

@dimitri320
Copy link

Any update on this issue? Our team is experiencing this problem as well, and I can see that it's already been a while, and so far I haven't seen any fixes.

@mhartington maybe you could have one of your team mates take a look at this issue? Our team has been struggling with this for a like 2-3 weeks already. Many thanks! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: react @ionic/react package type: bug a confirmed bug report
Projects
None yet
Development

No branches or pull requests

10 participants