0

Help I'm using a protected route in my React app. But it is not working. All the other Elements are working but when I got to "/account" the whole screen is white. This is my code. It will be really helpful for me if you give that answer. Thank You :)

Protected Route code:

import React, { Fragment } from 'react';
import { useSelector } from 'react-redux';
import { Route, Routes, redirect } from 'react-router-dom';



const ProtectedRoute = ({ element: Element, ...rest }) => {


    const { loading, isAuthenticated, user } = useSelector(state => state.user);



    return (
        <Fragment>

            {!loading && 
            
            
            (<Routes> 

                <Route 
                    {...rest}
                    
                    render={(props) => {

                        if(!isAuthenticated) {
                            return redirect("/login")
                        }

                        return <Element {...props} />
                    }}


                
                
                />
            
            </Routes>
            
            )}

        </Fragment>
    )
}

export default ProtectedRoute;

I am using ProtectedRoute.js in App.js. Here is the code. App.js Code:

import React from 'react';
import {BrowserRouter as Router,Route,Routes} from "react-router-dom"; 
import './App.css';
import Header from "./component/layout/Header/Header.js";
import webFont from "webfontloader";
import Footer from './component/layout/Footer/Footer';
import Home from "./component/Home/Home.js";
import ProductDetails from "./component/Product/ProductDetails.js";
import Products from "./component/Product/Products.js";
import Search from "./component/Product/Search.js";
import LoginSignUp from './component/User/LoginSignUp';
import store from "./store";
import { loadUser } from './action/userAction';
import UserOption from "./component/layout/Header/UserOption.js";
import { useSelector } from 'react-redux';
import Profile from "./component/User/Profile.js"
import ProtectedRoute from './component/Route/ProtectedRoute';

function App() {

  const {isAuthenticated, user} = useSelector(state => state.user)

React.useEffect(() => {


  webFont.load({
    google:{
      families:["Roboto","Droid Sans","Chilanka"]
    },
  });

  store.dispatch(loadUser())


}, [])


  return (
    
    <Router>
      
      <Header />
      {isAuthenticated && <UserOption 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 path="/account" element={ <ProtectedRoute> <Profile /> </ProtectedRoute> } />

        <Route path="/login" element={<LoginSignUp />} />


      </Routes>


      <Footer />
      
    </Router>
    
  );
}

export default App;

3 Answers3

2

In your App.js you can declare the protected route like this

<Route path="/account" element={ <ProtectedRoute /> } >
    <Route path="/account" element={ <Profile /> } >
</Route>

You can use Outlet of react-router v6 for passing the Component

const ProtectedRoute = ({ element: Element, ...rest }) => {

  const { loading, isAuthenticated, user } = useSelector(state => state.user);
        
  if (loading) {
      return <h2>Loading...</h2>
  }
  return isAuthenticated ? <Outlet /> : <Navigate to="/login" />;      

}
Kaneki21
  • 1,323
  • 2
  • 4
  • 22
  • Kaneki Thank you so much. The first solution ` } > } /> ` did work. I mean I can see the "./account" page now. But the layout or component inside of the page, I mean inside of the "./account" is not loading. – Sayedul Karim Oct 18 '22 at 13:51
  • Can you please check my ProtectedRoute code and tell me more clearly, where I should use Outlet or Navigate or Redirect? Thank You – Sayedul Karim Oct 18 '22 at 13:55
  • are you getting any error in browser console? – Kaneki21 Oct 18 '22 at 13:55
  • Yes. This is what am getting in the console " utils.ts:716 You rendered descendant (or called `useRoutes()`) at "/account" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. Please change the parent to . " – Sayedul Karim Oct 18 '22 at 14:58
  • Its clear in the error message `utils.ts:716 You rendered descendant (or called useRoutes()) at "/account" (under ) but the parent route path has no trailing `, you are using `` in the `Profile` component, you have to share it's code as well – Kaneki21 Oct 18 '22 at 15:11
  • I'm not using any Routes in Profile.js. It is just normal Fragment,div,h1,p etc tags – Sayedul Karim Oct 18 '22 at 16:24
0

I'm not sure, but you haven't pass any "element" prop to your ProtectedRoute component. You pass Profile component as children, so try render children instead of element in ProtectedRoute if you want your code to work like this.

I believe that you might want not to nest those routes, so also you might want to try use ProtectedRoute as Route in your router, I'm talking about something like this

    <Routes>
      ...

        <ProtectedRoute path="/account" element={<Profile />} />

      ...

    </Routes>

UPDATE

It might show you this error because your Route is conditionally rendered, so try to handle loading state in some other way, maybe something like this

           return (
                <Route 
                    {...rest}
                    
                    render={(props) => {

                        if(!isAuthenticated) {
                            return redirect("/login")
                        }
                        if(loading) {
                            return <LoadingComponent />
                        }

                        return <Element {...props} />
                    }}
                />
            )

0

@ Sayedul Karim.

I have a better and more concise way for this, An example of the code is below.

<Routes>
        <Route element={<App />}>
          {isAuthenticated ? (
            <>
              <Route path="/*" element={<PrivateRoutes />} />
              <Route
                index
                element={<Navigate to="/account" />}
              />
            </>
          ) : (
              <>
                <Route path="auth/*" element={<AuthPage />} />
                <Route path="*" element={<Navigate to="/auth" />} />
              </>
          )}
        </Route>
      </Routes>

In this way, you don't have to make any private component instead just make a component for private routes where the routes are defined.

The PrivateRoutes component will be like this

<Routes>
      <Route>
        {/* Redirect to account page after successful login */}
        {/* Pages */}
        <Route path="auth/*" element={<Navigate to="/account" />} />
        
        <Route path="account" element={<Account />} />
</Routes>

If any query further, feel free to ask....

  • Muhiq, Thank You so much for your answer bro. It's a clear code. But as a beginner, this is kinda confused to me. So that's why I prefer to use the privet method. But sure once I become an expert like you then I can use this method. – Sayedul Karim Oct 18 '22 at 15:05
  • Ok, for that also I have a simple code for Private and public routes in which I have used Outlet from react-router-dom. Here is the link for an [image consisting of the routing snippet](https://imgur.com/H1ov98p.png), Please refer to this. – Muhiq kapadia Oct 19 '22 at 06:43