I've got a React web app with routes defined via React Router.
The auth on the app is done with Firebase, and I want to protect certain routes depending upon whether a user is logged in or not.
To determine if the user is logged in, I have used the following function:
let user = firebase.auth().currentUser;
if (user) {
} else {
}
}
From there, I figured that I could put 'protected' routes in to the initial if as that would determine whether the user was logged in, like so:
let user = firebase.auth().currentUser;
if (user) {
<div>
<Route path="/dashboard" component={Dashboard} exact />
</div>
} else {
<Route path="/sign-in" component={SignIn} />
}
}
If the user isn't logged in, then they'd be re-directed to the sign in component.
This however isn't working. The dashboard page just comes back as a blank white screen instead of redirecting.
Indeed, an error message is displayed in the console:
Warning: Failed prop type: Invalid prop
childrensupplied toSwitch, expected a ReactNode.
For reference, here is my full component:
class App extends Component {
constructor(props) {
super(props)
this.userLoggedIn = this.userLoggedIn.bind(this)
}
userLoggedIn = () => {
let user = firebase.auth().currentUser;
if (user) {
<div>
<Route path="/dashboard" component={Dashboard} exact />
</div>
} else {
<Route path="/sign-in" component={SignIn} />
}
}
render() {
return (
<div>
<Switch>
{this.userLoggedIn}
<Route exact path="/" component={Homepage} />
<Route path="/sign-in" component={SignIn} />
<Route path="/register" component={Register} />
</Switch>
</div>
)
}
}
I know the logic is flawed, but is there a way I could refactor my code to implement this really straightforward hack to get protected routes using Firebase Auth?
Hope that's clear, let me know if any more info is needed.
EDIT: Edited my code in line with answer, but now receiving the following error message:
TypeError: Right side of assignment cannot be destructured
PrivateRoute
src/PrivateRoute.js:8
5 | import { AuthContext } from './Auth'
6 |
7 | export default function PrivateRoute({ component: RouteComponent, ...rest }) {
> 8 | const {currentUser} = useContext(AuthContext)
9 | return (
10 | <Route
11 | {...rest}
My updated code...
Auth.js
import React, { useEffect, useState } from 'react'
import * as firebase from "firebase/app";
import "firebase/auth";
import "firebase/firestore";
import firebaseConfig from './firebaseConfig';
export const AuthContext = React.createContext();
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState(null);
useEffect(() => {
firebase.auth().onAuthStateChanged(setCurrentUser);
}, []);
return (
<AuthContext.Provider
value={{currentUser}}
>
{children}
</AuthContext.Provider>
)
}
PrivateRoute.js
import React, { useContext } from 'react';
import { Route, Redirect } from 'react-router-dom';
import { AuthContext } from './Auth'
export default function PrivateRoute({ component: RouteComponent, ...rest }) {
const { currentUser } = useContext(AuthContext)
return (
<Route
{...rest}
render={routeProps =>
!!currentUser ? (
<RouteComponent {...routeProps} currentUser={currentUser} />
) : (
<Redirect to={'/signin'}/>
)
}
/>
)
}
App.js
import React, { Component } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import PrivateRoute from './PrivateRoute';
import './App.css';
import * as firebase from "firebase/app";
import "firebase/auth";
import "firebase/firestore";
import firebaseConfig from './firebaseConfig';
class App extends Component {
render() {
return (
<div>
<Switch>
<PrivateRoute path="/dashboard" component={Dashboard} />
<Route exact path="/" component={Homepage} />
<Route path="/sign-in" component={SignIn} />
<Route path="/register" component={Register} />
</Switch>
</div>
)
}
}
export default App;