I have an Ionic/React v5.0.7 app with IonReactRouter
to manage routing:
// App.tsx
return (
<IonApp>
<IonReactRouter history={history}>
<IonRouterOutlet>
<Route exact path={ROUTES.HOME} component={Home} />
<Route exact path={ROUTES.LOGIN} component={Login} />
<Route path={ROUTES.CONTRACTOR} component={ContractorDashboard} />
</IonRouterOutlet>
</IonReactRouter>
</IonApp>
)
In one of my routes (path={ROUTES.CONTRACTOR}
) I’m trying to implement IonTabs
which needs to have its own IonRouterOutlet
, so I have the tabs as nested routes like so:
// ContractorDashboard.tsx
<IonContent>
<IonTabs>
<IonTabBar slot="top">
<IonTabButton href="/contractor/overview" tab="contractor-overview">
<IonLabel>{t('ContractorDashboard.contractorOverview')}</IonLabel>
</IonTabButton>
<IonTabButton href="/contractor/contractor-configs" tab="contractor-configs">
<IonLabel>{t('ContractorDashboard.contractorConfig')}</IonLabel>
</IonTabButton>
<IonTabButton href="/contractor/workers-management" tab="workers-management">
<IonLabel>{t('ContractorDashboard.workersManagement')}</IonLabel>
</IonTabButton>
<IonTabButton href="/contractor/email-responses" tab="email-responses">
<IonLabel>Some label</IonLabel>
</IonTabButton>
</IonTabBar>
<IonRouterOutlet>
<Route path="/contractor/contractor-configs" render={() => <ContractorConfigs userId={authUser.uid} />} />
<Route path="/contractor/workers-management" component={WorkersManagement} />
<Route path="/contractor/email-responses" render={() => <EmailResponses userId={authUser.uid} />} />
<Route path="/contractor/contractor-overview" render={() => <IonTitle>Title</IonTitle>} />
<Route exact path="/contractor" render={() => <Redirect to="/contractor/overview" />} />
</IonRouterOutlet>
</IonTabs>
</IonContent>
Everything works fine until I try to create dynamic navigation to /contractor
route, which is the root of the tabs’ router, using history.push('/contractor')
or <Redirect to="/contractor" />
.
In my login component I want to redirect automatically to the ContractorDashboard
if a user is authenticated. I.e. after a successful login the user should be redirected to the dashboard. I implemented the following:
// Login.tsx
useEffect(() => {
if (authUser) {
history.push('/contractor')
}
}, [authUser, history])
What happens is the URL is changed in the address bar but the login page is still visible instead of the ContractorDashboard
. I also tried this:
// Login.tsx
if (authUser) {
return <Redirect to="/contractor"/>
}
return (
// ...
)
The result is the same. I can see the contractor page in the dev tools but it’s not rendered.
A few notes though:
- The result is a bit different when I try different things, like pushing to
/contractor/overview
insted of just/contractor
. Then the contractor dashboard is visible for a sec and then it’s the login page again. - Sometimes I do get the dashboard, but the tabs are not visible. Its in the DOM and the cursor events are there but still not visible.
- Everything was working before using
IonTabs
in the dashboard. - What’s weird is that when I try to navigate to the login page via the address bar with an authenticated user I’m redirected to the dashboard like I should and everything is working.
I did try replacing IonReactRouter
with Router
from react-router
like suggested in this answer. Then redirecting from the login page works but the tabs trigger a full page refresh on every tab change, which is just awful UX.
Here is my ionic info
output:
Ionic:
Ionic CLI : 6.11.0
Utility:
cordova-res : not installed
native-run : not installed
System:
NodeJS : v12.18.3
npm : 6.14.6
OS : Windows 10
and here’s my package.json
:
{
"name": "application",
"version": "0.0.1",
"private": true,
"dependencies": {
"@capacitor/android": "^2.4.6",
"@capacitor/core": "2.4.6",
"@ionic/react": "^5.0.7",
"@ionic/react-router": "^5.0.7",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.4.0",
"@testing-library/user-event": "^8.0.3",
"@types/jest": "^24.0.25",
"@types/node": "^12.12.24",
"@types/react": "^16.9.17",
"@types/react-dom": "^16.9.4",
"@types/react-router": "^5.1.4",
"@types/react-router-dom": "^5.1.3",
"firebase": "^8.2.3",
"i18next": "^19.8.4",
"i18next-http-backend": "^1.0.22",
"ionicons": "^5.0.0",
"react": "^16.13.0",
"react-dom": "^16.13.0",
"react-i18next": "^11.8.5",
"react-redux": "^7.2.2",
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
"react-scripts": "^4.0.1",
"redux": "^4.0.5",
"redux-localstorage-simple": "^2.3.1",
"redux-thunk": "^2.3.0",
"typescript": "3.8.3"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"appium": "appium --chromedriver-executable C:\\Users\\Ori\\code\\chromedrivers\\chromedriver-83-0-4103.exe",
"e2e:android": "protractor e2e/android-e2e.conf.js",
"e2e:web": "protractor e2e/web-e2e.conf.js"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@capacitor/cli": "2.4.6",
"@types/jasmine": "^3.6.3",
"@types/jasminewd2": "^2.0.8",
"@types/react-redux": "^7.1.15",
"@types/redux-logger": "^3.0.8",
"appium": "^1.20.2",
"jasmine": "^3.6.4",
"jasmine-spec-reporter": "^6.0.0",
"protractor": "^7.0.0",
"redux-logger": "^3.0.6",
"ts-node": "^9.1.1"
},
"description": "An Ionic project"
}
So is there a way to properly implement this and how?
Please let me know if any info or code is missing here.
Any help will be greatly appreciated!