英文:
How can I add React router to the content section in the main layout?
问题
function MainLayout() {
// ... (your existing code)
return (
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
{isLoading ? (
<Spin size="large" />
) : (
<Layout
style={{
minHeight: "100vh",
}}
>
{/* ... (your existing code) */}
{/* Remove the following line to prevent the infinite loop */}
{/* <AppRoutes/> PROBLEM HERE */}
{/* ... (your existing code) */}
</Layout>
)}
</div>
);
}
Note: I've commented out the problematic line <AppRoutes/>
as you requested.
英文:
I am developing application using React redux-toolkit. I added the route schema, and then I get the 'wow' error saying the page can't respond when it probably goes into an infinite loop. I have a MainLayout and I want to go to the content part of it by clicking the properties of the layout in the side menu. For example, the page that gives the list of registered cities when I click, the page that gives the names of the countries. I want to give these pages in the content section of the main layout. That's why I need to give you the route diagram that I have prepared. Since I also wrap routes in the app, I think it goes into an infinite loop because it wraps the route part twice, but I don't know how I can solve it. I need help.
function AppRoutes() {
return (
<Routes>
<Route element={<PrivateRoutes><MainLayout/></PrivateRoutes>} path="/">
{/* <Route element={<MainLayout/>} path="/"/> */}
</Route>
<Route element={<Login/>} path="/login"/>
<Route element={<CityList/>} path="/city/list"/>
<Route element={<Register/>} path="/register"/>
<Route element={<ActivateEmail/>} path="/account/activate"/>
<Route element={<NoMatch/>} path="*"/>
</Routes>
)
}
export default AppRoutes
const PrivateRoutes = ({children}) => {
const {userToken } = useSelector((state) => state.auth);
if(!userToken){
return <Navigate to="/login"/>
}else{
return children;
}
}
export default PrivateRoutes;
function App() {
const [locale, setLocale] = useState('tr');
return (
<IntlProvider locale={locale} messages={messages[locale]}>
<AppRoutes/>
</IntlProvider>
);
};
export default App
import { UserOutlined, FileOutlined, SettingOutlined, DownOutlined, LogoutOutlined } from "@ant-design/icons";
import { Breadcrumb, Layout, Menu, theme, Input, Space, Card, Button, Dropdown, message, Tag, Spin, Row, Col, Form } from "antd";
import { useState, useEffect } from "react";
import { RiLockPasswordLine } from 'react-icons/ri'
import {AiOutlineMenu} from 'react-icons/ai'
import { useDispatch, useSelector } from "react-redux";
import { getUserbyId, signOut } from "../utils/api.service";
import { useNavigate } from 'react-router-dom';
import { getTokenSub } from '../utils/HelperFunctions';
import { getUser, userInfo } from '../types/user';
import { useIntl } from "react-intl";
import AppRouteList from "../routes/AppRouteList";
import FormButton from "../components/FormButton";
import InputDisableText from "../components/InputDisableText";
import AppRoutes, { RouteApp } from "../routes/AppRoutes";
const { Header, Content, Footer, Sider } = Layout;
export function MainLayout() {
const {userToken } = useSelector((state) => state.auth);
const intl = useIntl();
const navigate = useNavigate();
const menuItemClick = (e) => {
switch(e.key){
case "menu_city_list":
navigate("/city/list")
break;
default:
break;
}
}
function getItem(label, key, icon, children) {
return {
key,
icon,
children,
label,
};
}
const items = [
getItem("Faturalar", "sub1", <FileOutlined />, [
getItem("Team 1", "1"),
getItem("Team 2", "2"),
]),
getItem("Sistem Ayarları", "sub2", <SettingOutlined />, [
getItem("Ülkeler", "5"),
getItem(intl.formatMessage({id:"menu_city_list"}),"menu_city_list",<AiOutlineMenu/>),
getItem("Client", "7"),
getItem("Tom", "8"),
getItem("Bill", "9"),
getItem("Alex", "10"),
getItem("Tom", "11"),
// getItem("Bill", "12"),
// getItem("Alex", "13"),
// getItem("Tom", "14"),
getItem("Genel Ayarlar", "15"),
]),
getItem("Hesabım", "sub3", <UserOutlined />, [
getItem("Hesabım", "3"),
getItem("Oturum Kapat", "4"),
]),
];
const handleButtonClick = (e) => {
message.info('Click on left button.');
console.log('click left button', e);
};
const handleMenuClick = (e) => {
message.info('Click on menu item.');
console.log('click', e);
};
const [isLoading, setIsLoading] = useState(false);
const token = localStorage.getItem('userToken');
const sub = getTokenSub(token);
const dispatch = useDispatch();
getUser.Id = sub
useEffect(() => {
dispatch(getUserbyId(getUser)).then((result) => {
userInfo.id = result.payload.id
userInfo.clientId = result.payload.clientId
userInfo.clientName = result.payload.clientName
userInfo.email = result.payload.email
userInfo.firstName = result.payload.firstName
userInfo.lastName = result.payload.lastName
userInfo.isActive = result.payload.isActive
userInfo.normalizedEmail = result.payload.normalizedEmail
userInfo.userName = result.payload.userName
userInfo.passwordChangeTime = result.payload.passwordChangeTime
});
}, [dispatch, getUser])
useEffect(() => {
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
}, 1000);
}, []);
const handleLogout = () => {
dispatch(signOut())
};
const itemsDropDown = [
{
label: 'Hesabım',
key: '100',
icon: <UserOutlined />,
},
{
label: 'Şifremi Değiştir',
key: '200',
icon: <RiLockPasswordLine />,
},
{
label: 'Oturum Kapat',
key: '400',
icon: <LogoutOutlined />,
danger: true,
onClick: handleLogout
},
];
const menuProps = {
items: itemsDropDown,
// onClick: handleMenuClick,
};
const [collapsed, setCollapsed] = useState(false);
const {
token: { colorBgContainer },
} = theme.useToken();
return (
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
{isLoading ? (
<Spin size="large" />
) : (
<Layout
style={{
minHeight: "100vh",
}}
>
{console.log("user ınfo", userToken)}
<Sider
collapsible
collapsed={collapsed}
onCollapse={(value) => setCollapsed(value)}
>
<div
style={{
height: 32,
margin: 16,
background: "rgba(255, 255, 255, 0.8)",
}}
>
</div>
<Menu
theme="dark"
defaultSelectedKeys={["1"]}
mode="inline"
items={items}
onClick={menuItemClick}
/>
</Sider>
<Layout className="site-layout">
<Header
style={{
padding: 0,
background: colorBgContainer,
}}
>
</Header>
<Content
style={{
margin: "0 16px",
}}
>
{/* <AppRoutes/> PROBLEM HERE */}
</div>
</Content>
<Footer
</Footer>
</Layout>
</Layout>
)}
</div>
);
}
When I open the AppRoutes component in the comments line in the content on the main layout page, it enters an endless loop and the browser stops responding and gives an error.
答案1
得分: 0
AppRoutes
渲染 MainLayout
,当渲染另一个 AppRoutes
时,再次渲染另一个 MainLayout
... 你看到问题了吗?这会通过无限递归创建一个“渲染循环”。
我怀疑你的意图是让 MainLayout
渲染一个用作布局路由的 Outlet
组件,它可能作为布局路由渲染。
如果你打算让 MainLayout
成为所有路由的布局路由组件,那么它应该包装所有路由。PrivateRoute
组件也应该转换为布局路由组件,以便它可以包装应该受保护的所有路由。
PrivateRoutes
组件如下:
import { Navigate, Outlet } from 'react-router-dom';
const PrivateRoutes = () => {
const { userToken } = useSelector((state) => state.auth);
return userToken ? <Outlet /> : <Navigate to="/login" replace />;
}
AppRoutes
组件如下:
function AppRoutes() {
return (
<Routes>
<Route element={<Login />} path="/login" />
<Route element={<Register />} path="/register" />
{/* ... 其他非主布局路由 */}
<Route element={<MainLayout />}>
<Route element={<ActivateEmail />} path="/account/activate" />
{/* ... 其他不受保护的路由 */}
<Route element={<PrivateRoutes />}>
<Route element={<CityList />} path="/city/list" />
{/* ... 其他受保护的路由 */}
</Route>
<Route element={<NoMatch />} path="*" />
{/* ... 其他主布局路由 */}
</Route>
</Routes>
)
}
英文:
AppRoutes
renders MainLayout
which when rendering another AppRoutes
renders another MainLayout
... do you see the problem? This creates a "render loop" by infinite recursion.
I suspect you meant for MainLayout
to render an Outlet
component for nested routes it may be rendering as a layout route.
import { Outlet } from 'react-router-dom';
...
export function MainLayout() {
...
return (
<div style={{ .... }}>
{isLoading ? (
<Spin size="large" />
) : (
<Layout style={{ .... }}>
...
<Layout className="site-layout">
<Header style={{ .... }} />
<Content style={{ .... }}>
<Outlet /> // <-- for nested route content
</Content>
<Footer />
</Layout>
</Layout>
)}
</div>
);
}
If you are intending for MainLayout
to be a layout route component for all routes then it should wrap all routes. The PrivateRoute
component should also be converted to a layout route component so it can wrap all routes that should be protected.
import { Navigate, Outlet } from 'react-router-dom';
const PrivateRoutes = () => {
const { userToken } = useSelector((state) => state.auth);
return userToken ? <Outlet /> : <Navigate to="/login" replace />;
}
function AppRoutes() {
return (
<Routes>
<Route element={<Login />} path="/login" />
<Route element={<Register />} path="/register" />
{/* ... other non-main-layout routes */}
<Route element={<MainLayout />}>
<Route element={<ActivateEmail />} path="/account/activate" />
{/* ... other unprotected routes */}
<Route element={<PrivateRoutes />}>
<Route element={<CityList />} path="/city/list" />
{/* ... other protected routes */}
</Route>
<Route element={<NoMatch />} path="*" />
{/* ... other main-layout routes */}
</Route>
</Routes>
)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论