Skip to content

[Bug]: Wrapper for component passed in the "element" prop for the <Route /> does not re-render when switching routes #8551

Closed
@kuubson

Description

@kuubson

What version of React Router are you using?

6.2.1

Steps to Reproduce

I've tested this code with clear cra typescript template to make sure none of dependencies or app logic affects this behavior but a bug described below still occurs there.

import React, { useEffect } from "react";
import { BrowserRouter, Routes, Route, useNavigate } from "react-router-dom";

const Profile = () => {
  useEffect(() => {
    console.log("profile");
  }, []);
  return <div>profile</div>;
};

const Chat = () => {
  useEffect(() => {
    console.log("chat");
  }, []);
  return <div>chat</div>;
};

const Navbar = () => {
  const navigate = useNavigate();
  return (
    <nav>
      <h1 onClick={() => navigate("/")}>Profile</h1>
      <h1 onClick={() => navigate("/chat")}>Chat</h1>
    </nav>
  );
};

const ProtectedRoute: React.FC = ({ children }) => {
  useEffect(() => {
    console.log(
      'this should log every time we switch between "/" and "/profile" route'
    );
  }, []);
  return (
    <div>
      <Navbar />
      {children}
    </div>
  );
};

const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route
          path="/"
          element={
            <ProtectedRoute>
              <Profile />
            </ProtectedRoute>
          }
        />
        <Route
          path="/chat"
          element={
            <ProtectedRoute>
              <Chat />
            </ProtectedRoute>
          }
        />
      </Routes>
    </BrowserRouter>
  );
};

export default App;

Expected Behavior

Component ProtectedRoute should fire its console.log from useEffect every time I switch between / and /profile routes.

It doesn't work because the ProtectedRoute isn't re-rendered.

Only those nested components within ProtectedRoute are re-rendered. (Profile and Chat )

Actual Behavior

When I pass element to the Route like that:

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

it only re-renders Profile component when switching routes: console.log from Profile component fires but console.log from ProtectedRoute does not.

When I pass it this way:

const ProfileRoute = () => (
  <ProtectedRoute>
    <Profile />
  </ProtectedRoute>
);

<Route path="/" element={<ProfileRoute />} />

It start re-rendering both ProtectedRoute and Profile when switching between routes so both console.logs start working

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions