reactjs React-Router-Dom 6 -如何动态呈现组件?

falq053o  于 2023-01-17  发布在  React
关注(0)|答案(3)|浏览(233)

我的老方法:

<Route
            key={i}
            path={path}
            render={(props) => {
              if (!localStorage.getItem("token")) {
                <Redirect
                to={{ pathname: "/login", state: { from: props.location } }}
                />
              }
              return (
                <AuthLayout>
                  <Component {...props} />
                </AuthLayout>
              );
            }}
          />

render替换为新的element,得到:
函数作为React子级无效。如果返回组件而不是从呈现返回组件,则可能会发生这种情况
显然,新的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 },

当我尝试在循环中返回Component时,得到:
React.jsx:类型无效--应为字符串(对于内置组件)或类/函数(对于复合组件),但得到:您可能忘记从定义组件的文件中导出组件,或者您可能混淆了默认导入和命名导入。

pvcm50d1

pvcm50d11#

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>
)}
ql3eal8s

ql3eal8s2#

element属性需要ReactNode(* 又名JSX ),而不是javascript( 即if语句 *)。
由于您似乎是批量呈现已验证的路由,因此更理想的解决方案是将它们全部 Package 在一个检查令牌的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" />;
};

不要忘记从map回调中返回Route

<Route element={<AuthLayout token={token} />}>
  {authProtectedRoutes.map(({ path, Component }) => (
    <Route key={path} path={path} element={<Component />} />
  ))}
</Route>
gmol1639

gmol16393#

很好的路由相关问题。首先,我从react-router-dom的github中找到了有用的代码示例:https://github.com/remix-run/react-router/blob/2cd8266765925f8e4651d7caf42ebe60ec8e163a/examples/auth/src/App.tsx#L104
在这里,作者建议实现额外的RequireAuth组件并在路由设置中使用它,而不是将一些逻辑放在“element”或“render”中,如下所示:

<Route
  path="/protected"
  element={
    <RequireAuth>
      <SomePageComponent />
    </RequireAuth>
  }
....

这种方法将允许在这个新的RequireAuth组件中封装与身份验证相关的检查,从而使您的应用程序路由设置更加“轻量级”
作为一个“简短”的例子,我创建了以下代码,您可以参考:

function App() {
    return (
        <BrowserRouter>
            <AppRoutes />
        </BrowserRouter>
    );
}

const RequireAuth = ({ children }) => {
    const token = localStorage.getItem('token');
    const currentUrl = useHref();
    return !token ? (
        <Navigate to={`/login?redirect=${currentUrl}`} />
    ) : (
        children
    );
};

const authProtectedRoutes = [
    { path: '/', component: PaymentsPage },
    { path: '/user', component: UserInfoPage },
];

const AppRoutes = () => (
    <Routes>
        {authProtectedRoutes.map((r) => (
            <Route
                key={r.path}
                path={r.path}
                element={
                    <RequireAuth>
                        <AuthLayout>
                            <r.component />
                        </AuthLayout>
                    </RequireAuth>
                }
            />
        ))}
        <Route path="/login" element={<LoginPage />} />
        <Route path="*" element={<NotFoundPage />} />
    </Routes>
);

相关问题