An Ionic React application is useless in a browser until this bug is fixed.
This issue is a problem in both versions of @ionic/react 7.4 and 7.5.
I have two simple routes defined as follows:
<IonRouterOutlet id="main">
...
<Route path="/campaigns" exact={true} render={props => <CampaignList {...props} />} />
<Route path="/campaign/:title" exact={true} render={props => <CampaignDetail {...props} />} />
...
</IonRouterOutlet>
The first route displays a list and each list item has an onClick
method defined which calls a method titled getCampaignDetail
which navigates to the second route as follows:
const getCampaignDetail = (title:string) => {
navigate(`/campaign/${title}`, 'root');
}
When i load my app, it defaults to /campaigns
That view loads without issue and displays the list
If i tap a list item it correctly navigates to /campaign/:title
Then, i use the browser’s back button to load /campaigns
The /campaigns
view loads without issue
Then, upon tapping a different list item i can say that i am absolutely positive that it attempts to load a different :title
because:
- i am console logging the value before it navigates and seeing the value is clearly different
- The URL in the browser clearly is showing as though the parameter
:title
is different and has changed from the last time i visited this route
Despite this, when i console log the :title
in the CampaignDetail
component which is what loads at /campaign/:title
inside it’s useIonViewDidEnter
method, the :title
is printing as though its value has not changed from the first time i visited /campaign:title
In my CampaignDetail
component i have tried retrieving the parameter in one of 2 ways, first directly from props:
type MatchParams = {
title: string;
};
const CampaignDetail: React.FC<RouteComponentProps> = (props) => {
const { title } = props.match.params as MatchParams;
...
And also with the useParams
hook:
const CampaignDetail: React.FC<RouteComponentProps> = (props) => {
const { title } = useParams<{ title: string; }>();
...
and it is in the useIonViewDidEnter
method, where i am attempting to console log :title
useIonViewDidEnter(() => {
console.log("PARAMETER:", title);
});
This behavior only occurs after having used the browser’s back button.
Why is the parameter not reflecting the correct value for subsequent visits after having used the browser’s back button?
In an attempt to fix this after reading documentation and doing other research into this issue I have tried adding a key
to the route as a solution as follows:
<Route path="/campaign/:title" exact={true} render={props => <CampaignDetail key={props.match.params.title} {...props} />} />
however, this results in EVEN WORSE BEHAVIOR in that after having used the browsers back button subsequent visits to /campaign:title
cause the useIonViewDidEnter
method to execute several times and with each execution i am seeing the :title
act as if it is toggling between the two values i have visited with each print to the console. First i see the value as it was for the first time i visited, then the new value, then it prints the first value and so on about 3-4 times before it finally stops.
Seeing that behavior speaks volumes in that having used the browser’s back button clearly causes strange behavior with respect to route parameters.
What can i do to fix this?
UPDATE:
I am noticing that when i hit the browser’s back button while at the route /campaign/:title
that the useIonViewDidEnter
function in the component CampaignDetail
is firing again when it should not given that i had left that route and navigated back to /campaigns
.
OTHER ODD BEHAVIOR:
As per @Aafaq’s suggestion that i check location
as a means of troubleshooting, i did this and have discovered strange behavior as a result.
If i comment out the useIonViewDidEnter
method all together and use the following useEffect
hook with location
to check for path changes as follows:
const campaignDetailTitleRef = useRef('');
useEffect(() => {
const parts = location.pathname.split('/');
const getPathTitle = parts[2];
if (getPathTitle && getPathTitle !== campaignDetailTitleRef.current) {
campaignDetailTitleRef.current = getPathTitle;
console.log("PARAMETER:", getPathTitle);
}
},[location.pathname]);
When the app loads which launches the route /campaigns
and then i click on a list item, i see that console.log("PARAMETER:", getPathTitle);
only prints once as expected when /campaign/:title
loads and it is displaying the correct value as it was parsed from location
.
Then i hit the browser’s back button, and subsequently, i click a different list item, and while the value of getPathTitle
is actually printing correct now having retrieved that value from location
instead of params, i am seeing console.log("PARAMETER:", getPathTitle);
print twice which tells me that either campaignDetailTitleRef.current = getPathTitle
is not getting set after the hook runs the first time or the component is loading twice, it is hard to tell which is the case. It is difficult to troubleshoot what is happening.
Something as simple as page navigation with just one dynamic parameter in the url should not be so difficult. This renders Ionic React worthless in a browser at this time.
2
Answers
It seems that wrapping routes with the
<Switch>
component makes sure that only one route is matched at a time and works to prevent the behavior i described.I will suggest you to use the useLocation hook from react-router-dom to log the current location and its state for debugging purposes. This can help you identify any unexpected behavior related to route changes. Example given below: