ionic-framework: bug: react - maximum depth exceeded from PrivateRoute
Bug Report
Ionic version: [ ] 4.x [x] 5.x
Current behavior: Redirecting from a PrivateRoute causes “Maximum update depth exceeded”.
Expected behavior: Redirect to, for example, a “/login” page.
I have been trying to use the PrivateRoute pattern described here without success.
Steps to reproduce:
ionic start ionic-react-redirect-bug conference --type=react
cd ionic-react-redirect-bug
Add the following to src/App.tsx:
interface PrivateRouteProps extends RouteProps {
component: any;
}
const PrivateRoute = ({component: Component, ...rest}: PrivateRouteProps) => {
const isLoggedIn = false;
return (
<Route
{...rest}
render={(routeProps) =>
isLoggedIn ? (
<Component {...routeProps} />
) : (
<Redirect to={{pathname: "/login", state: {from: routeProps.location}}}/>
)
}
/>
);
}
In src/App.tsx replace:
<Route path="/support" component={Support} />
with:
<PrivateRoute path="/support" component={Support} />
Comment out useEffect in src/components/Map.tsx if it complains about anything (unrelated to this issue).
ionic serve
Click the Support menu item.
Other information:
In the browser console:
Uncaught Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
React 4
unlisten react-router.js:69
listener history.js:162
notifyListeners history.js:180
notifyListeners history.js:179
setState history.js:300
replace history.js:414
confirmTransitionTo history.js:152
replace history.js:397
onUpdate react-router.js:309
componentDidUpdate react-router.js:189
React 6
unstable_runWithPriority scheduler.development.js:659
React 5
unstable_runWithPriority scheduler.development.js:659
React 6
Ionic info:
Ionic:
Ionic CLI : 6.10.1 (/usr/local/lib/node_modules/@ionic/cli)
Ionic Framework : @ionic/react 5.2.3
Capacitor:
Capacitor CLI : 1.3.0
@capacitor/core : 1.3.0
Utility:
cordova-res : not installed
native-run : 1.0.0
System:
NodeJS : v14.4.0 (/usr/local/Cellar/node/14.4.0/bin/node)
npm : 6.14.6
OS : macOS Catalina
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 2
- Comments: 18 (9 by maintainers)
Commits related to this issue
- fix: According to https://github.com/ionic-team/ionic-framework/issues/21717#issuecomment-1144889727 — committed to m3thom/maximum-depth-exceeded-reproduce by m3thom 2 years ago
Awesome, I am going to close this issue out as completed, as the main issue reported is resolved.
If any run into any other issues, feel free to open a new issue and the team would be happy to take a look.
Hello @m3thom looking into this issue again.
I believe the routing structure may be a driving factor to the issue here.
The
/loginpage does not fit within mobile tabs navigation rules. The route is a root route, but is being rendered inside of the tabs router outlet, having the tab bar being displayed when the route is active. The tab bar should only be displayed for tab pages, or sub-pages of tabs (that are within the stack).There are two valid solutions I see with this use case:
Login is a root route outside of the tabs outlet
Treating the
/loginpage as a page outside of the tabs outlet will result in the page being full height (not displaying the tab bar). This pattern is most often use when the entire tabs experience is protected by authentication.e.g.:
<video src="https://user-images.githubusercontent.com/13732623/201206944-952dfece-c028-4397-9cdb-fa9455cf33e2.mp4"></video>
I did have to tweak some of the logic around the location state, repro: https://github.com/sean-perkins/ionic-gh-21717
Use a modal in place of a protected route
If the true desire is to allow unauthenticated users to access tab 1 and tab 2, but have to sign into access tab 3, a modal experience that takes over the fullscreen when tab 3 is activated would be desired.
I experimented with trying to render the private route inside of the tab3 routing structure, but this leads to other problems, that activating the tab bar button for tab3 attempts to route to
/tab3, but is redirected to/tab3/loginwhen unauthenticated. This results in a push transition which looks bad and is probably an anti-pattern for navigation.Can you try either of these suggestions and let me know if that resolves your issue or if you observe anything else?
I tried this in App.tsx which stopped the error:
<Redirect to={{pathname: "/login", state: {from: {pathname: routeProps.location.pathname}}}}/>And this in Login.tsx:
But as seen from the log, the value is overwritten so the redirect won’t work:
Hi @jeffcjohnson,
I noticed passing in the routeProps.location to the state is what is seeming to cause an infinite render somewhere inside react router. This is happening because the value of
locationchanges each render. Are you able to pull off just the pathname from location, instead of passing the whole object?: