skip to Main Content

I am new in React and React router. My problem is, after click on Login button, Home component does not render. It justs replace url adress from "/" to "/home".

Packages are all installed right. I have checked this out in Network in DevTools, and it really does not render Home component

Why it is happening?

AppRoutes.js

const AppRoutes = [
  {
        index: true,
        path: "/",
        element: <Layout />
    },
    {
        path: "/home",
        element: <Home/>
    }
];

export default AppRoutes;

Layout.jsx

const Layout = () => {

    const [userId, setUserId] = useState(null);
    const navigate = useNavigate();

    const getUserIdFromLocalStorage = async () => {
    const id = await localStorage.getItem('userId');

        if (!id) {
            navigate('/');
        } else {
            setUserId(id);
        }
    };

      useEffect(() => {
         
          getUserIdFromLocalStorage();

      }, []);

      return (
          <>
              {userId ? (
                  <>
                      <Sidebar />
                  </>
              ) : (
                  <LoginPage />
              )}
          </>
      );
    }
export default Layout;

LoginPage

const LoginPage =  () => {

    const navigate = useNavigate();

    const redirectToHome = () => {
        navigate('/home',
            {
                replace: true
            });
    }
        return (
            <div className="bg-dark text-white">
                <button onClick={redirectToHome}>Login</button>
            </div>
        );
    }
export default LoginPage;

App

export default class App extends Component {
  static displayName = App.name;

  render() {
      return (
          <Routes>
              <Route element={<Layout />}>
                  {AppRoutes.map((route, index) => {
                      const { path, element } = route;
                      return <Route key={index} path={path} element={element} />;
                  })}
              </Route>
          </Routes>
    );
  }
}

2

Answers


  1. There are two issues.

    1. You need to have those Routes wrapped inside a router context.
    2. Remove Layout route since you already have that in AppRoutes object.
    import React, { Component } from "react";
    import { Routes, Route, BrowserRouter } from 'react-router-dom';
    
    export default class App extends Component {
      static displayName = App.name;
    
      render() {
        const AppRoutes = [
          {
            path: "/home",
            element: <Home />
          },
          {
            path: "/",
            element: <Layout />
          }
        ];
        
        return (
          <BrowserRouter>
            <Routes>
              {AppRoutes.map((route, index) => {
                  const { path, element } = route;
                  return <Route key={index} path={path} element={element} />;
                })}
            </Routes>
          </BrowserRouter>
        );
      }
    }
    
    Login or Signup to reply.
  2. Issue

    The issue here is that you are rendering Layout on a layout route, e.g. a route that renders nested routes, and Layout is not rendering an Outlet component for the nested routes to render their element content into.

    Suggested Solutions

    You have a few options:

    1. Refactor Layout to render an Outlet so the nested routes can also be outputted. Remove the layout route from AppRoutes.
    2. Keep Layout as a regular route component and remove the "parent" layout route.

    Between the two I believe you really want to keep Layout as a layout route. Refactor it to render the Sidebar and an Outlet or a redirect to a "/login" route that renders Login.

    const Layout = () => {
      const [userId, setUserId] = useState(() => {
        // lazy load initial state from localStorage
        return localStorage.getItem('userId');
      });
    
      const navigate = useNavigate();
    
      if (userId === undefined) {
        return null; // or loading indicator, spinner, etc...
      }
    
      return userId
        ? (
          <>
            <Sidebar />
            <div id="main-content">
              <Outlet />
            </div>
          </>
        ) : <Navigate to="/login" replace />;
    }
    
    export default Layout;
    
    const AppRoutes = [
      {
        element: <Layout />,
        children: [
          {
            path: "/",
            element: <Home />
          },
          {
            path: "/login",
            element: <LoginPage />
          }
        ],
      },
    ];
    
    export default AppRoutes;
    
    export default class App extends Component {
      static displayName = App.name;
    
      render() {
        return (
          <Routes>
            {AppRoutes.map((route, index) => {
              return <Route key={index} {...route} />;
            })}
          </Routes>
        );
      }
    }
    

    or convert App to a React function component and use the useRoutes hook. No need to reinvent the wheel of mapping/rendering routes.

    const App = () => {
      const routes = useRoutes(AppRoutes);
    
      return routes;
    }
    
    export default App;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search