React-Router-Dom 6 - 如何动态渲染组件?
React-Router-Dom 6 - How to dynamically render a component?
我的旧方法:
<Route
key={i}
path={path}
render={(props) => {
if (!localStorage.getItem("token")) {
<Redirect
to={{ pathname: "/login", state: { from: props.location } }}
/>
}
return (
<AuthLayout>
<Component {...props} />
</AuthLayout>
);
}}
/>
用新的 element
替换 render
得到:
Functions are not valid as a React child. This may happen if you return a Component instead of from render
显然新的 API 只是期望:
<Route
key={i}
path={path}
element={
<Component />
}
/>
我真正想要完成的是动态渲染组件:
{authProtectedRoutes.map(({ path, Component }, i) => {
<Route
key={i}
path={path}
element={
// If no auth token, redirect to login
if (!token) {
<Navigate to="/login" />
} else {
<AuthLayout>
<Component />
</AuthLayout>
}
}
/>
})}
不知道该怎么做...
编辑:
我的组件数组是这样的:
const authProtectedRoutes = [
{ path: "/dashboard", Component: Dashboard },
{ path: "/pages-starter", Component: StarterPage },
当我在循环中尝试 return Component
时,我得到:
React.jsx: type is invalid -- expected a string (for built-in
components) or a class/function (for composite components) but got:
undefined. You likely forgot to export your component from the file
it's defined in, or you might have mixed up default and named imports.
element={
// If no auth token, redirect to login
if (!token) {
<Navigate to="/login" />
} else {
<AuthLayout>
<Component />
</AuthLayout>
}
}
你不能在jsx中间做一个if
,但是你可以做一个条件运算符:
element={!token ? (
<Navigate to="/login" />
) : (
<AuthLayout>
<Component />
</AuthLayout>
)}
element
道具需要 ReactNode
(a.k.a.JSX) 而不是 javascript ( 即 if-statement).
由于您似乎批量呈现经过身份验证的路由,因此更优化的解决方案是将它们全部包装在一个检查令牌的 AuthLayout
组件中。它不是渲染 children
道具,而是渲染一个 Outlet
来渲染要渲染到的嵌套路由。
示例:
const AuthLayout = ({ token }) => {
// ... existing AuthLayout logic
return token
? (
<div /* awesome auth layout CSS style */>
...
<Outlet /> // <-- nested routes render here
</div>
)
: <Navigate to="/login" />;
};
不要忘记从地图回调中 return Route
。
<Route element={<AuthLayout token={token} />}>
{authProtectedRoutes.map(({ path, Component }) => (
<Route key={path} path={path} element={<Component />} />
))}
</Route>
我的旧方法:
<Route
key={i}
path={path}
render={(props) => {
if (!localStorage.getItem("token")) {
<Redirect
to={{ pathname: "/login", state: { from: props.location } }}
/>
}
return (
<AuthLayout>
<Component {...props} />
</AuthLayout>
);
}}
/>
用新的 element
替换 render
得到:
Functions are not valid as a React child. This may happen if you return a Component instead of from render
显然新的 API 只是期望:
<Route
key={i}
path={path}
element={
<Component />
}
/>
我真正想要完成的是动态渲染组件:
{authProtectedRoutes.map(({ path, Component }, i) => {
<Route
key={i}
path={path}
element={
// If no auth token, redirect to login
if (!token) {
<Navigate to="/login" />
} else {
<AuthLayout>
<Component />
</AuthLayout>
}
}
/>
})}
不知道该怎么做...
编辑:
我的组件数组是这样的:
const authProtectedRoutes = [
{ path: "/dashboard", Component: Dashboard },
{ path: "/pages-starter", Component: StarterPage },
当我在循环中尝试 return Component
时,我得到:
React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
element={
// If no auth token, redirect to login
if (!token) {
<Navigate to="/login" />
} else {
<AuthLayout>
<Component />
</AuthLayout>
}
}
你不能在jsx中间做一个if
,但是你可以做一个条件运算符:
element={!token ? (
<Navigate to="/login" />
) : (
<AuthLayout>
<Component />
</AuthLayout>
)}
element
道具需要 ReactNode
(a.k.a.JSX) 而不是 javascript ( 即 if-statement).
由于您似乎批量呈现经过身份验证的路由,因此更优化的解决方案是将它们全部包装在一个检查令牌的 AuthLayout
组件中。它不是渲染 children
道具,而是渲染一个 Outlet
来渲染要渲染到的嵌套路由。
示例:
const AuthLayout = ({ token }) => {
// ... existing AuthLayout logic
return token
? (
<div /* awesome auth layout CSS style */>
...
<Outlet /> // <-- nested routes render here
</div>
)
: <Navigate to="/login" />;
};
不要忘记从地图回调中 return Route
。
<Route element={<AuthLayout token={token} />}>
{authProtectedRoutes.map(({ path, Component }) => (
<Route key={path} path={path} element={<Component />} />
))}
</Route>