I am using Ionic Framework, and Firebase in a React and Typescript project and coming across the error 'An Ionic Router is required for IonRouterContext' when trying to navigate after successful auth login.
I have tried removing the AppRoutes file and having it all in App.tsx but still experiencing the error.
App.tsx
const App: React.FC = () => {
return (
<IonApp>
<IonReactRouter>
<IonRouterOutlet>
<AppRoutes />
</IonRouterOutlet>
</IonReactRouter>
</IonApp>
)
}
export default App
appRoutes.tsx
import React from 'react'
import { Route } from 'react-router-dom'
import { IonRouterOutlet } from '@ionic/react'
import Dashboard from '@/pages/dashboard'
import SignUp from '@/components/onboarding/signup'
import Login from '@/components/onboarding/login'
import Landing from '@/components/onboarding/landing'
const AppRoutes: React.FC = () => {
return (
<IonRouterOutlet>
<Route exact path="/" component={Landing} />
<Route exact path="/onboarding" component={Landing} />
<Route exact path="/signup" component={SignUp} />
<Route exact path="/login" component={Login} />
<Route exact path="/dashboard" component={Dashboard} />
</IonRouterOutlet>
)
}
export default AppRoutes
landing.tsx (the routes here to go to the login and signup components work)
import React from 'react'
import { IonContent, IonButton, IonPage, IonNavLink } from '@ionic/react'
import '@/styles/onboarding/landing.scss'
import SignUp from './signup'
import Login from './login'
const Landing: React.FC = () => {
return (
<>
<IonContent fullscreen>
<div className="container">
<div className="buttons ion-float-bottom">
<IonNavLink routerDirection="forward" component={() => <SignUp />}>
<IonButton className="signup-btn" fill="solid" expand="block">
Create an account
</IonButton>
</IonNavLink>
<IonNavLink routerDirection="forward" component={() => <Login />}>
<IonButton className="login-btn" fill="outline" expand="block">
Sign In
</IonButton>
</IonNavLink>
</div>
</div>
</IonContent>
</>
)
}
export default Landing
login.tsx
import React, { useState } from 'react'
import { IonPage, IonContent, IonHeader, IonInput, IonButton, IonItem, IonButtons, IonBackButton, useIonRouter } from '@ionic/react'
import { loginUser } from '@/auth/firebase'
import '@/styles/onboarding/login.scss'
const Login: React.FC = () => {
const router = useIonRouter()
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState<string | null>(null)
const handleLogin = async () => {
try {
const user = await loginUser(email, password)
if (user) {
// Login successful, redirect to dashboard
router.push('/dashboard')
} else {
setError('Invalid email or password')
}
} catch (error) {
console.log(`---error:`, error)
setError('Error logging in')
}
}
return (
<IonPage className="login-page">
<IonHeader>
<IonButtons slot="start">
<IonBackButton defaultHref="/" />
</IonButtons>
</IonHeader>
<IonContent className="ion-padding">
<IonItem>
<IonInput type="email" placeholder="Email" value={email} onIonChange={e => setEmail(e.detail.value!)} />
</IonItem>
<IonItem>
<IonInput type="password" placeholder="Password" value={password} onIonChange={e => setPassword(e.detail.value!)} />
</IonItem>
{error && <p style={{ color: 'red' }}>{error}</p>}
<IonButton id="login-button" expand="block" onClick={handleLogin}>
Login
</IonButton>
</IonContent>
</IonPage>
)
}
export default Login
router.push('/dashboard')
is the problem here and is giving me that error. Is my structure incorrect?
1 Remove the Nested IonRouterOutlet: You should only have one IonRouterOutlet in your app. The IonRouterOutlet should wrap the routes defined in AppRoutes.
2 Correct App Structure: Here’s how you can modify your App.tsx and AppRoutes.tsx to eliminate the nested IonRouterOutlet:
App.tsx:
import React from 'react';
import { IonApp } from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
import AppRoutes from './AppRoutes';
const App: React.FC = () => {
return (
<IonApp>
<IonReactRouter>
<AppRoutes />
</IonReactRouter>
</IonApp>
);
}
export default App;
AppRoutes.tsx:
import React from 'react';
import { Route } from 'react-router-dom';
import { IonRouterOutlet } from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
import Dashboard from '@/pages/dashboard';
import SignUp from '@/components/onboarding/signup';
import Login from '@/components/onboarding/login';
import Landing from '@/components/onboarding/landing';
const AppRoutes: React.FC = () => {
return (
<IonRouterOutlet>
<Route exact path="/" component={Landing} />
<Route exact path="/onboarding" component={Landing} />
<Route exact path="/signup" component={SignUp} />
<Route exact path="/login" component={Login} />
<Route exact path="/dashboard" component={Dashboard} />
</IonRouterOutlet>
);
}
export default AppRoutes;
Summary of Changes:
Removed the extra IonRouterOutlet in AppRoutes.tsx. The IonRouterOutlet in App.tsx now directly contains the routing logic.
Ensure that IonReactRouter only wraps the main routing outlet, making it available for navigation.