React-router v6 路由组成。是否可以呈现自定义路线?

问题描述 投票:0回答:3

出于学习目的,我正在尝试使用 React-Router v6 创建一个受保护的自定义路由。正如许多人在我之前在论坛或此处尝试过的那样,我收到此错误:Error: [ProtectedRoute] is not a component.

此外,如果有人正在为不可重用的实现而苦苦挣扎,可以在下面查看我的工作代码:我的问题是我真的希望它可以重用,这样我就可以避免使用这种混乱的代码。如果您有任何想法,请告诉我。

我个人认为这是不可能的,因为当前的 V6 实现。也许他们将来会让我们这样做。但我希望这篇文章无论如何都能帮助那些希望保护路由的人,尤其是在使用 Parse 平台时。

自定义路线:

const ProtectedRoute = ({ component: Component, ...rest }) => {
  return (
    <Route
      {...rest}
      render={(props) => {
        <AuthWrapper>
          <Component {...rest} {...props} />
        </AuthWrapper>;
      }}
    />
  );
};

如果用户当前未登录,包装器使用 Parse Server 来保护路由。

const AuthWrapper = ({ children }) => {
  if (Parse.User.current() !== null) {
    let isAuthenticated = Parse.User.current().getSessionToken();
    let authCondition = isAuthenticated !== undefined;
    if (authCondition) {
      return children;
    }
  }
  return <Navigate to={"/login"} />;
};

export default AuthWrapper;

没有自定义路线的工作解决方案:(没有

<ProtectedRoute />
的ofc)

<Route
  path="/book"
  element={
    <AuthWrapper>
       <BookPage />
    </AuthWrapper>
  }
/>

我想做的是:

<ProtectedRoute
    path={'/path'}
    element={<Anything/>}
/>
javascript reactjs parse-platform react-router react-router-dom
3个回答
8
投票

react-router-dom
v6 不,而且我不怀疑它会支持自定义路由组件,就像以前版本中使用的那样,现在更喜欢组合。您已经正确地创建了一个包含一些内容的
AuthWrapper
组件,这是文档中的 v6 身份验证示例

但它可以改进。您可以返回一个

children
来渲染嵌套的
Outlet
组件,而不是返回单个
Route
节点。这会将
AuthWrapper
组件从包装器组件转换为布局组件。

import { Navigate, Outlet } from 'react-router-dom';

const AuthLayout = () => {
  if (Parse.User.current() !== null) {
    const isAuthenticated = Parse.User.current().getSessionToken();
    return isAuthenticated ? <Outlet /> : null; // or loading indicator, etc...
  }
  return <Navigate to={"/login"} replace />;
};

这允许您将单个

AuthLayout
组件渲染到
Route
中,并在其中嵌套任意数量的受保护路由。

<Route element={<AuthLayout />}>
  <Route path="/book" element={<BookPage />} />
  ... other protected routes ...
</Route>

0
投票

我认为这会解决它。你错过了渲染道具中的回报。

const ProtectedRoute = ({ component: Component, ...rest }) => {
  return (
    <Route
      {...rest}
      render={(props) => {
        return (<AuthWrapper>
          <Component {...rest} {...props} />
        </AuthWrapper>);
      }}
    />
  );
};

0
投票

我通过做两件事做到了

  • 创建扩展路由对象(RouteObject with my own props)
  • 映射他们
    • 通过添加具有保护和自定义逻辑的包装器
    • 从 ExtendedRouteObject 过滤回 RouteObject

所以,这是我的代码

// Overwrite is my custom type in order to override any type i need
type TExtendedRouteObject = Overwrite<
  RouteObject,
  {
    children?: TExtendedRouteObject[];
  }
> & {
  /**
   * In order to set to document.title
   */
  title: string;
};

const mapExtendedRoutes = (routeObjects: TExtendedRouteObject[]): RouteObject[] => {
  if (routeObjects.length) {
    return routeObjects.map(route => {
      if (route.children?.length) {
        return omit({
          ...route,
          element: <RouteWrapper {...route} />,
          children: mapExtendedRoutes(route.children),
        },
        ['title'],
      ) as RouteObject;
      }

      return omit({ // omit from lodash.omit
        ...route,
        element: <RouteWrapper {...route} />,
      }) as RouteObject;
    });
  }

  return [];
};

const RouteWrapper: FC<TExtendedRouteObject> = ({ element, title }) => {
  useEffect(() => {
    document.title = title;
  }, [title]);

  // your auth logic goes here

  return <>{element}</>;
};

const extendedRoutes: TExtendedRouteObject[] = [
  {
    path: '/',
    title: 'Homepage',
    element: <Dashboard />,
    children: [...],
  },
...
];

const routes: RouteObject[] = mapExtendedRoutes(extendedRoutes);

const router = createBrowserRouter(routes);
// then pass it to <RouterProvider router={router} />
© www.soinside.com 2019 - 2024. All rights reserved.