简体   繁体   English

将 React 路由组织成单独的组件

[英]Organizing React routes into separate components

I'm trying to find a way to organize my routes to assist the dev who might be taking over my work in the future.我正在尝试找到一种方法来组织我的路线,以帮助将来可能接管我工作的开发人员。 I thought of separating my <Route /> entries into separate components and then just load those into a main component similar to how users are assigned groups.我想将我的<Route />条目分成单独的组件,然后将它们加载到类似于用户分配组的主要组件中。

The issue is that when using more than one component only the first one works.问题是,当使用多个组件时,只有第一个组件有效。 This might not be the most react way of doing this so I'm also open to alternatives.这可能不是最有效的方式,所以我也愿意接受替代方案。

Original route arrangement原路线安排

const AllRoutes = () => {
    return (
        <Switch>
            {/* public routes*/}
            <Route path={'/about'} component={AboutView} />
            <Route path={'/project'} component={ProjectView} />
            <Route path={'/contact'} component={ContactView} />
            
            {/* auth routes */}
            <Route path={'/login'} component={LoginView} />
            <Route path={'/logout'} component={LogoutView} />

            <Route component={Error404View} />
        </Switch>
    )
}

Separating the public routes from the auth ones:将公共路由与认证路由分开:

const PublicRouteGroup = () => {
    return (
        <>
            <Route path={'/about'} component={AboutView} />
            <Route path={'/project'} component={ProjectView} />
            <Route path={'/contact'} component={ContactView} />
        </>
    )
}

const AuthRouteGroup = () => {
    return (
        <>
            <Route path={'/login'} component={LoginView} />
            <Route path={'/logout'} component={LogoutView} />
        </>
    )
}

This way I can use it as such:这样我就可以这样使用它:

const AllRoutes = () => {
    return (
        <Switch>
            <PublicRouteGroup />    {/* This works */}
            <AuthRouteGroup />      {/* This doesn't */}


            {/* This 404 is not a route group */}
            <Route component={Error404View} />
        </Switch>
    )
}

Flipping <PublicRouteGroup /> and <AuthRouteGroup /> only changes the order:翻转<PublicRouteGroup /><AuthRouteGroup />只会改变顺序:

const AllRoutes = () => {
    return (
        <Switch>
            <AuthRouteGroup />      {/* This works */}
            <PublicRouteGroup />    {/* This doesn't */}

            {/* This 404 is not a route group */}
            <Route component={Error404View} />
        </Switch>
    )
}

Update #1更新#1

This is thanks to @skyboyer.这要感谢@skyboyer。 By moving the <Switch> to the child components and removing it from the AllRoutes component each component started to show.通过将<Switch>移动到子组件并将其从每个组件开始显示的AllRoutes组件中删除。 It appears adding the <Switch> in AllRoutes is allowing only the first hit to show which is as <Switch> does.似乎在AllRoutes中添加<Switch>只允许第一个命中显示与<Switch>一样。 But now by removing it it shows the 404 at the end of each page as well.但是现在通过删除它,它也会在每页的末尾显示 404。

Basically, it looks like this:基本上,它看起来像这样:

const AllRoutes = () => {
    return (
        <>
            <Route component={AuthRouteGroup} />      {/* This works */}
            <Route component={PublicRouteGroup} />    {/* This also works */}

            {/* This 404 is not a route group */}
            <Route component={Error404View} />        {/* Always shown at the bottom */}
            {/* Even putting the 404 in its own RouteGroup yields the same issue */}
        </>
    )
}

It appears this current set up of treating components like OOP classes you can extend from is the wrong approach.看来,当前处理组件(如您可以扩展的 OOP 类)的设置是错误的方法。 I've instead made use of arrays since these can be acted upon by the spread operator.我改用了 arrays 因为这些可以由扩展运算符执行。 It still accomplishes the same goal of organizing routes across an infinite number of groups which was what I was after.它仍然实现了在无限数量的组中组织路线的相同目标,这正是我所追求的。

Create the array for each group为每个组创建数组

const public_route_group = [
    {path: '/about', component: AboutView},
    {path: '/project', component: ProjectView},
    {path: '/contact', component: ContactView},
]

const auth_route_group = [
    {path: '/login', component: LoginView},
    {path: '/logout', component: LogoutView},
]

const error_route_group = [
    {component: Error404View}   // No path required
]

const user_routes = [
    ...public_route_group,
    ...auth_route_group,
    ...error_route_group
]

Create the routes创建路线

const AllRoutes = () => {
    return (
        <Switch>
            {user_routes.map((route, idx) => {
                return <Route key={idx} {...route} />
            })}
        </Switch>
    )
}

I figure this can also be modified further if you're using nested objects in your array.如果您在数组中使用嵌套对象,我认为这也可以进一步修改。

I'd like to thank @skyboyer for providing an insight into this problem.我要感谢@skyboyer 提供了对这个问题的见解。

How about having it without Swtich at top-level没有顶级的Swtich怎么样

  <Route component={PublicRouteGroup} />
  <Route component={AuthRouteGroup} />      

so they are rendered unconditionally.所以它们被无条件地渲染。 And then having extra Switch in your components like然后在您的组件中添加额外的Switch ,例如


const AuthRouteGroup = () => {
    return (
        <Switch>
            <Route path={'/login'} component={LoginView} />
            <Route path={'/logout'} component={LogoutView} />
        <Switch/>
    )
}

But why id did not work?但为什么 id 不起作用?

The reason is how Switch works :原因是Switch的工作原理

React.Children.forEach(this.props.children, child => {
  if (match == null && React.isValidElement(child)) {
    element = child;
    const path = child.props.path || child.props.from;

    match = path
      ? matchPath(location.pathname, { ...child.props, path })
      : context.match;
  }
});

See, even if AuthRouteGroup is not a Route , Switch anyway looks to its props.path .看,即使AuthRouteGroup不是RouteSwitch无论如何都会查看它的props.path And once undefined for props.path matches any path and Switch renders only first matching Route you are getting only first component rendered.一旦undefined for props.path匹配任何路径并且Switch只呈现第一个匹配的Route ,您只会得到第一个呈现的组件。

[UPD] "does-not-match-any-route" View will work only at top level of Switch . [UPD] "does-not-match-any-route" 视图仅适用于Switch的顶层。 Also there are no way to know if some nested children of sibling element has matched current route or not.也没有办法知道兄弟元素的一些嵌套子元素是否与当前路由匹配。 So only way I see is listing all routes in single place.所以我看到的唯一方法是在一个地方列出所有路线。

Alternative that looks rather poor is having special route "/error404" and redirect user to it from inside of other components(but who should decide? and where? and when?).看起来相当糟糕的替代方案是具有特殊的路由“/error404”并将用户从其他组件内部重定向到它(但谁应该决定?在哪里?何时?)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM