英文:
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 />
来渲染应用程序的布局。但是在路由更改时,Menu
和Header
也会重新渲染。是否有解决方法可以阻止这些组件的重新渲染?
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 <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?
答案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 = () => {
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>
);
};
答案2
得分: 1
如果您担心在路由更改时Menu
和Header
与ProtectedRoutes
一起重新渲染,那么我建议将它们分离成另一个布局组件,以便它们的重新渲染与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 = () => (
<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>
);
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论