I'm trying to use ProtectedRoute as I can't see why the code isn't working, I'm not getting any error, but at /account
it should display <Profile/>
and it's blank, I can see the header and footer, but the whole <Profile/>
is missing before trying to use a PrivateRoute
, I could display Profile
with any problem.
my ProtectedRoute.js
import React from "react";
import { useSelector } from "react-redux";
import { Navigate, Outlet } from "react-router-dom";
const ProtectedRoute = () => {
const {isAuthenticated} = useSelector((state)=>state.user)
return isAuthenticated ? <Outlet /> : <Navigate to="/login"/>
}
export default ProtectedRoute;
my app.js
function App() {
const {isAuthenticated, user} = useSelector(state=>state.user)
React.useEffect(() => {
WebFont.load({
google:{
families: [ "Droid Sans", "Chilanka"],
},
});
store.dispatch(loadUser())
}, []);
return (
<Router>
<Header/>
{isAuthenticated && <UserOptions user={user} />}
<Routes>
<Route exact path="/" element={<Home/>}/>
<Route exact path="/product/:id" element={<ProductDetails/>}/>
<Route exact path="/products" element={<Products/>}/>
<Route path="/products/:keyword" element={<Products/>}/>
<Route exact path="/search" element={<Search/>}/>
<Route exact path="/account" element={<ProtectedRoute/>}/>
<Route exact path="/account" element={<Profile/>}/>
<Route exact path="/login" element={<LoginSignUp/>}/>
</Routes>
<Footer/>
</Router>
);
}
export default App;
and my Profile
const Profile = () => {
const { user, loading, isAuthenticated} = useSelector((state) => state.user);
const navigate = useNavigate();
useEffect(() => {
if(isAuthenticated === false){
navigate("/login");
}
}, [navigate,isAuthenticated])
return (
<Fragment>
<MetaData title={`${user.name}'s Profile`} />
<div className="profileContainer">
<div>
<h1>My Profile</h1>
<img src={user.avatar?.url} alt={user.name} />
<Link to="/me/update">Edit Profile</Link>
</div>
<div>
<div>
<h4>Full Name</h4>
<p>{user.name}</p>
</div>
<div>
<h4>Email</h4>
<p>{user.email}</p>
</div>
<div>
<h4>Joined On</h4>
<p>{String(user.createdAt).substr(0, 10)}</p>
</div>
<div>
<Link to="/orders">My Orders</Link>
<Link to="/password/update">Change Password</Link>
</div>
</div>
</div>
</Fragment>
);
};
export default Profile;
You are rendering two routes for the same "/account"
path. ProtectedRoute
is rendered on its own self-closing route, so the second route rendering Profile
is unreachable.
<Routes>
<Route exact path="/" element={<Home/>}/>
<Route exact path="/product/:id" element={<ProductDetails/>}/>
<Route exact path="/products" element={<Products/>}/>
<Route path="/products/:keyword" element={<Products/>}/>
<Route exact path="/search" element={<Search/>}/>
<Route exact path="/account" element={<ProtectedRoute/>}/>
<Route exact path="/account" element={<Profile/>}/> // <-- unreachable, oops!
<Route exact path="/login" element={<LoginSignUp/>}/>
</Routes>
Remove the path
prop from the layout route rendering the ProtectedRoute
and ensure it is actually wrapping other Route
components. You may as well also remove the exact
prop on all the routes as this prop was removed in RRDv6.
Example:
<Router>
<Header/>
{isAuthenticated && <UserOptions user={user} />}
<Routes>
<Route path="/" element={<Home />} />
<Route path="/product/:id" element={<ProductDetails />} />
<Route path="/products" element={<Products />} />
<Route path="/products/:keyword" element={<Products />} />
<Route path="/search" element={<Search />} />
<Route element={<ProtectedRoute />}>
<Route path="/account" element={<Profile />} /> // <-- wrapped by layout route!
</Route>
<Route path="/login" element={<LoginSignUp />} />
</Routes>
<Footer/>
</Router>
The ProtectedRoute
component doesn't appear to wait for the user
state to populate before rendering either the Outlet
for protected content or the redirect. Apply some conditional rendering to render a loading indicator or similar while the user
state is populated.
import React from "react";
import { useSelector } from "react-redux";
import { Navigate, Outlet } from "react-router-dom";
const ProtectedRoute = () => {
const user = useSelector((state) => state.user);
if (!user) return null; // <-- or loading indicator, etc...
return user.isAuthenticated
? <Outlet />
: <Navigate to="/login" replace />;
}
export default ProtectedRoute;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.