React Router v6 使用 `` 来防止重新渲染路由周围的组件。

huangapple go评论75阅读模式
英文:

React Router v6 prevent rerendering components around Routes using <Outlet />

问题

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.

我正在尝试创建一个完全受保护的React应用程序。只有在登录之前才能访问登录页面。但它的布局与应用程序的其余部分完全不同。

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?

我只是使用<Outlet />来渲染应用程序的布局。但是在路由更改时,MenuHeader也会重新渲染。是否有解决方法可以阻止这些组件的重新渲染?

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?

我应该将LoginRoute组件完全分离出Routes,并在userData存在的情况下有条件地显示它,还是有其他解决方案?

英文:

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 &lt;Outlet /&gt; 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 = () =&gt; {
    return (
        &lt;Routes&gt;
            &lt;Route path=&quot;/&quot; index={true} element={&lt;LoginRoute /&gt;} /&gt;

            &lt;Route element={&lt;ProtectedRoutes /&gt;}&gt;
                &lt;Route path=&quot;dashboard&quot; index={true} element={&lt;Dashboard /&gt;} /&gt;
                &lt;Route path=&quot;article&quot; element={&lt;ArticleRoute /&gt;} /&gt;
                &lt;Route path=&quot;article/add&quot; element={&lt;ArticleAddRoute /&gt;} /&gt;
                &lt;Route path=&quot;article/:id&quot; element={&lt;ArticleEditRoute /&gt;} /&gt;
            &lt;/Route&gt;

            &lt;Route path=&quot;*&quot; element={&lt;ErrorPage /&gt;} /&gt;
        &lt;/Routes&gt;
    );
};

ProtectedRoutes

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

    return userData ? (
        &lt;Container&gt;
            &lt;NavContainer&gt;
                &lt;Menu /&gt;
            &lt;/NavContainer&gt;
            &lt;Main&gt;
                &lt;Header /&gt;
                &lt;div&gt;
                    &lt;Outlet /&gt;
                &lt;/div&gt;
            &lt;/Main&gt;
        &lt;/Container&gt;
    ) : (
        &lt;Navigate to=&quot;/&quot; state={{ from: location, status: &#39;unauthorized&#39; }} replace /&gt;
    );
};

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

答案1

得分: 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>
  );
};
英文:

I guess that they are rerendering because you use useLocation

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

  return userData ? (
    &lt;TopBar /&gt;
  ) : (
    &lt;Navigate
      to=&quot;/&quot;
      state={{ from: location, status: &quot;unauthorized&quot; }}
      replace
    /&gt;
  );
};

const TopBar = () =&gt; {
  return (
    &lt;Container&gt;
      &lt;NavContainer&gt;
        &lt;Menu /&gt;
      &lt;/NavContainer&gt;
      &lt;Main&gt;
        &lt;Header /&gt;
        &lt;div&gt;
          &lt;Outlet /&gt;
        &lt;/div&gt;
      &lt;/Main&gt;
    &lt;/Container&gt;
  );
};

答案2

得分: 1

如果您担心在路由更改时MenuHeaderProtectedRoutes一起重新渲染,那么我建议将它们分离成另一个布局组件,以便它们的重新渲染与ProtectedRoutes组件的重新渲染解耦。

示例:

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>
  );
};
英文:

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 = () =&gt; (
  &lt;Container&gt;
    &lt;NavContainer&gt;
      &lt;Menu /&gt;
    &lt;/NavContainer&gt;
    &lt;Main&gt;
      &lt;Header /&gt;
      &lt;div&gt;
        &lt;Outlet /&gt;
      &lt;/div&gt;
    &lt;/Main&gt;
  &lt;/Container&gt;
);
const ProtectedRoutes = () =&gt; {
  const { userData } = useAuth();
  const location = useLocation();

  return userData
    ? &lt;Outlet /&gt;
    : (
      &lt;Navigate
        to=&quot;/&quot;
        state={{ from: location, status: &#39;unauthorized&#39; }}
        replace
      /&gt;
    );
};
const App = () =&gt; {
  return (
    &lt;Routes&gt;
      &lt;Route path=&quot;/&quot; element={&lt;LoginRoute /&gt;} /&gt;

      &lt;Route element={&lt;AppLayout /&gt;}&gt;
        &lt;Route element={&lt;ProtectedRoutes /&gt;}&gt;
          &lt;Route path=&quot;dashboard&quot; element={&lt;Dashboard /&gt;} /&gt;
          &lt;Route path=&quot;article&quot; element={&lt;ArticleRoute /&gt;} /&gt;
          &lt;Route path=&quot;article/add&quot; element={&lt;ArticleAddRoute /&gt;} /&gt;
          &lt;Route path=&quot;article/:id&quot; element={&lt;ArticleEditRoute /&gt;} /&gt;
        &lt;/Route&gt;
      &lt;/Route&gt;

      &lt;Route path=&quot;*&quot; element={&lt;ErrorPage /&gt;} /&gt;
    &lt;/Routes&gt;
  );
};

huangapple
  • 本文由 发表于 2023年6月21日 23:41:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/76525026.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定