I have a Class App.js, with elements SignInAndSignUpPage ("/signin") and HomePage ("/"). When a user logs in (through a Firebase db), I'd like to make the login/SignInAndSignUp page become inaccessible until they click a Sign Out button in a Header element.
render() {
return (
<div>
<Header />
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/shop" element={<ShopPage />} />
<Route path="/signin" element={<SignInAndSignUpPage />} />
{/* pass the currentUser state as a prop */}
{this.props.currentUser
? ((<Route path="/" element={<HomePage />} />),
console.log(`"current user info:" ${this.props.currentUser}`))
: ((<Route path="/signin" element={<SignInAndSignUpPage />} />),
console.log("sign in"))}
</Routes>
</div>
);
}
I'm trying to use a ternary operator to determine if this.props.currentUser is not null, then route to the HomePage. If it's null, go to the SignInAndSignUp page.
Logging shows me that this.props.currentUser is not null, and it drops into the correct call (<Route path="/" element={<HomePage />} />)
when it's supposed to, but still the login page is rendered.
Removing the <Route path="/signin" element={<SignInAndSignUpPage />} />
call only removes the child components inside SignInAndSignUp but still doesn't route to HomePage.
Another way to put it, what I'm trying to achieve, is when a user logs in the page should be routed to the home page, and if they're currently logged in and try to manually update the url to get to the /signin page, they should be routed to the home page.
EDIT: Tried the ternary operator and the PrivateRoute, neither seemed to work. The ternary operator is commented out right now. Here's what the console is outputting, at least in regard to the action and payload. Payload would be null if currentUser was null.
render() {
return (
<div>
<Header />
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/shop" element={<ShopPage />} />
<Route path="/signin" element={<SignInAndSignUpPage />} />
<Route
path="/"
element={
<PrivateRoute currentUser={this.props.currentUser}>
<HomePage />
</PrivateRoute>
}
/>
{/* <Route
path="/"
element={
this.props.currentUser ? <HomePage /> : <Navigate to="/signin" />
}
/> */}
{/* pass the currentUser state as a prop */}
{/* {this.props.currentUser
? ((<Route path="/" element={<HomePage />} />),
console.log(`"current user info:" ${this.props.currentUser}`))
: ((<Route path="/signin" element={<SignInAndSignUpPage />} />),
console.log("sign in"))} */}
</Routes>
</div>
);
}
}
Here's the code for the PrivateRoute:
import React from "react";
import { Navigate } from "react-router";
const PrivateRoute = ({ children, ...props }) => {
return props.currentUser ? children : <Navigate to="signin" />;
};
export default PrivateRoute;
CodePudding user response:
If you want to use a ternary operator you can do it inside the element prop like so:
<Route path="/" element={this.props.currentUser ? <Homepage /> : <Navigate to="signin" />} />
You will obviously have to import { Navigate } from 'react-router-dom'
otherwise you could probably make a custom protected route component to redirect to the signup page like so:
import { Navigate } from 'react-router-dom';
const PrivateRoute = ({ children, ...props }) => {
return props.currentUser
? children
: <Navigate to='/signin' /> }
}
export default PrivateRoute;
then use that like
<Route path="/" element={
<PrivateRoute currentUser={this.props.currentUser}>
<Homepage />
</PrivateRoute>
} />
CodePudding user response:
Ok, I figured it out. I kept getting this error in the console 'React router did not match any routes /signin', and I believe that's because with <Navigate to='/signin/ /> I never declared the element anywhere in my route declarations.
const PrivateRoute = ({ children, ...props }) => {
return props.currentUser
? children
**: <Navigate to='/signin' /> }**
}
So, I updated to:
const PrivateRoutes = ({ children, ...props }) => {
return !props.currentUser ? children : <Navigate to="/" />;
};
If currentUser is null, render the (SignInAndSignUp) children, otherwise Navigate to '/'.
App.js updates:
render() {
return (
<div>
<Header />
<Routes>
<Route path="/" element={<HomePage />} />
<Route
path="/signin"
element={
<PrivateRoutes currentUser={this.props.currentUser}>
<SignInAndSignUpPage />
</PrivateRoutes>
}
/>
<Route path="/shop" element={<ShopPage />} />
</Routes>
</div>
);
}
I have to leave <Route path="/" element={<HomePage />} />
in the declaration because otherwise I get the 'React router did not match any routes' error. I realize this seems odd, backwards even, but reversing it so the PrivateRoutes navigates to HomePage instead doesn't seem to work. Thoughts are definitely welcome as I realize this isn't the greatest of code.