skip to Main Content

I am trying to create a fully protected React application. Only Login page should be available without login. However it has a completely different layout than rest of the application.

I am using simply <Outlet /> for rendering the app layout. However on route change, the Menu and Header are also rerendering. Is there a solution how to prevent the rerender of these components?

App

const App = () => {
    return (
        <Routes>
            <Route path="/" index={true} element={<LoginRoute />} />

            <Route element={<ProtectedRoutes />}>
                <Route path="dashboard" index={true} element={<Dashboard />} />
                <Route path="article" element={<ArticleRoute />} />
                <Route path="article/add" element={<ArticleAddRoute />} />
                <Route path="article/:id" element={<ArticleEditRoute />} />
            </Route>

            <Route path="*" element={<ErrorPage />} />
        </Routes>
    );
};

ProtectedRoutes

const ProtectedRoutes = () => {
    const { userData } = useAuth();
    const location = useLocation();

    return userData ? (
        <Container>
            <NavContainer>
                <Menu />
            </NavContainer>
            <Main>
                <Header />
                <div>
                    <Outlet />
                </div>
            </Main>
        </Container>
    ) : (
        <Navigate to="/" state={{ from: location, status: 'unauthorized' }} replace />
    );
};

Should I separate the LoginRoute component completely out of the Routes and showing it conditionally if userData exists or is there any other solution?

2

Answers


  1. I guess that they are rerendering because you use useLocation

    const ProtectedRoutes = () => {
      const { userData } = useAuth();
      const location = useLocation();
    
      return userData ? (
        <TopBar />
      ) : (
        <Navigate
          to="/"
          state={{ from: location, status: "unauthorized" }}
          replace
        />
      );
    };
    
    const TopBar = () => {
      return (
        <Container>
          <NavContainer>
            <Menu />
          </NavContainer>
          <Main>
            <Header />
            <div>
              <Outlet />
            </div>
          </Main>
        </Container>
      );
    };
    
    Login or Signup to reply.
  2. If you are concerned about the Menu and Header being possibly rerendered along with the ProtectedRoutes when the routes change, then I’d suggest separating them out into another layout component so their rerendering is decoupled from ProtectedRoutes component rerenders.

    Example:

    const AppLayout = () => (
      <Container>
        <NavContainer>
          <Menu />
        </NavContainer>
        <Main>
          <Header />
          <div>
            <Outlet />
          </div>
        </Main>
      </Container>
    );
    
    const ProtectedRoutes = () => {
      const { userData } = useAuth();
      const location = useLocation();
    
      return userData
        ? <Outlet />
        : (
          <Navigate
            to="/"
            state={{ from: location, status: 'unauthorized' }}
            replace
          />
        );
    };
    
    const App = () => {
      return (
        <Routes>
          <Route path="/" element={<LoginRoute />} />
    
          <Route element={<AppLayout />}>
            <Route element={<ProtectedRoutes />}>
              <Route path="dashboard" element={<Dashboard />} />
              <Route path="article" element={<ArticleRoute />} />
              <Route path="article/add" element={<ArticleAddRoute />} />
              <Route path="article/:id" element={<ArticleEditRoute />} />
            </Route>
          </Route>
    
          <Route path="*" element={<ErrorPage />} />
        </Routes>
      );
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search