【问题标题】:React: how to structure routes for admin, user and publicReact:如何为管理员、用户和公共构建路由
【发布时间】:2020-04-15 23:37:07
【问题描述】:

我试图弄清楚如何构造一个路由器,以便为管理员、用户和公共使用不同的路由。

我看到this post 和描述钥匙斗篷的答案 - 但我无法理解它。

我看过这个code sandbox,这对我来说看起来很合乎逻辑,但我在整合它时遇到了麻烦。

我有一个常量文件,我将路由定义为:

export const NEWBLOG = '/admin/newblog';
export const VIEWBLOG = '/viewblog';

我将其导入到我的 App.js 中,然后想为 Admin、User 和 Public 定义不同的 const,如下所示:

import * as ROUTES from '../../util/constants/Routes';
import NewBlog from '../../components/blog/admin/New';

// admin routes
const Admin = ({ match }) => (
  <React.Fragment>
    <Route path={`${match.path}/${ROUTES.NEWBLOG}`} component={NewBlog} />
    <Route path={`${match.path}/2`} render={() => <h2>test</h2>} />
  </React.Fragment>
);

// authenticated user routes
const Other = ({ match }) => (
  <React.Fragment>
    <Switch>
      <Route path={`${match.path}/2`} render={() => <h2>one</h2>} />
      <Route path={`${match.path}/2`} render={() => <h2>two</h2>} />
    </Switch>
  </React.Fragment>
);

// public routes
const Public = ({ match }) => (
  <React.Fragment>
    <Switch>
      <Route path={`${match.path}/2`} render={() => <h2>one</h2>} />
      <Route path={`${match.path}/2`} render={() => <h2>two</h2>} />
    </Switch>
  </React.Fragment>
);

然后在路由器语句中我有:

const App = () => (

    <Router>
        <Navigation />
        <Switch>

            <Route path="/a" component={Admin} />
            <Route path="/u" component={Other} />
            <Route path="/p" component={Public} />

            <Route
                component={({ location }) => {
                  return (
                    <div
                      style={{
                        padding: "50px",
                        width: "100%",
                        textAlign: "center"
                      }}
                    >
                      <ErrorMessage />
                    </div>
                  );
                }}
              />
        </Switch>

    </Router>

);

export default App;

这一切都有效,直到我尝试使用 Admin 常量的反引号部分内的路由常量。

我似乎无法使用这种方法。

任何人都可以提供参考资料来源以找到解决方法吗?

【问题讨论】:

  • 怎么不工作?为什么不为NEWBLOG 常量定义特定的路由部分,比如const NEWBLOG = 'newblog' 而不是const NEWBLOG = '/admin/newblog'
  • 我在代码中是这样定义的,但只是想在示例中使其更清晰。停止它工作的部分是后面的 ROUTES.NEWBLOG 标记
  • 它有效,你可以检查它here,它在大括号字符串文字中有ROUTES.NEWBLOG。我看到的问题是您在NEWBLOG 变量中定义了整个路由,例如/admin/newblog

标签: reactjs react-router


【解决方案1】:

有几件事你需要知道

  1. 子路由只有在父路由路径匹配时才会渲染
  2. 对于子路由,路径必须是匹配父路由路径 + 子路由路径的路径
  3. 您可以在路由上编写包装器,这些包装器负责决定用户是经过身份验证还是管理员身份
  4. 在所有此类场景中,您需要将用户身份验证状态存储在状态、上下文或 redux 存储中。
  5. 当您在 Admin 中渲染路由时,例如
<Route path={`${match.path}/${ROUTES.NEWBLOG}`} component={NewBlog} />

组件的路径实际上变成了/a/admin/newBlog,这实际上是不正确的

总体而言,您可以将代码更改为这样的内容

App.js

const App = () => (
    <Router>
        <Navigation />
        <Switch>
            <Route path="/admin" component={Admin} />
            <Route path="/user" component={Other} />
            <Route path="/public" component={Public} />
        </Switch>
    </Router>
);

AuthRoute.js

const AuthRoute = (props) => {
   const {path, match, component: Component, render, ...rest} = props;
   const {user, isLoading} = useContext(AuthContext); // Assuming you use context to store route, you can actually get this values from redux store too.
   return (
      <Route
          {...rest}
          path={`${match.path}${path}`}
          render={(routerProps) => {
               if(isLoading) return <div>Loading...</div>
                if(!user) return <div>Not Authenticated</div>
               return Component? <Component {...rest} {...routerProps} /> : render(routerProps)
          }}
      />

}

一个 adminRoute 需要检查用户是否是管理员以及检查他是否经过身份验证,以便您的组件看起来像

AdminRoute.js

const AdminRoute = (props) => {
   const {path, match, ...rest} = props;
   const {user, isLoading} = useContext(AuthContext); // Assuming you use context to store route, you can actually get this values from redux store too.
   return (
      <Route
          {...rest}
          path={`${match.path}${path}`}
          render={(routerProps) => {
               if(isLoading) return <div>Loading...</div>
               if(!user) return <div>Not Authenticated</div>
               if(user.role !== "admin") return <div>Need to be an admin to access this route</div>
               return Component? <Component {...rest} {...routerProps} /> : render(routerProps)
          }}
      />

}

现在你可以使用上面两个组件来分离 Admin 和 Auth Routes

另外请记住,AuthRoutes 和公共路由路径不能相同

路由常量

export const NEWBLOG = '/newblog';
export const VIEWBLOG = '/viewblog';

路线

import * as ROUTES from '../../util/constants/Routes';
import NewBlog from '../../components/blog/admin/New';

// admin routes
const Admin = (props) => (
  <React.Fragment>
    <AdminRoute {...props} path={ROUTES.NEWBLOG} component={NewBlog} />
    <AdminRoute {...props} path='/2' render={() => <h2>test</h2>} />
  </React.Fragment>
);

// authenticated user routes
const Other = (props) => (
  <React.Fragment>
    <Switch>
      <AuthRoute {...props} path={'/3'} render={() => <h2>one</h2>} />
      <AuthRoute {...props} path={'/4'} render={() => <h2>two</h2>} />
    </Switch>
  </React.Fragment>
);

// public routes
const Public = ({ match }) => (
  <React.Fragment>
    <Switch>
      <Route path={`${match.path}/5`} render={() => <h2>one</h2>} />
      <Route path={`${match.path}/6`} render={() => <h2>two</h2>} />
    </Switch>
  </React.Fragment>
);

【讨论】:

  • 非常感谢您。我早上试试。同时,如果您能给我一个参考以尝试理解什么,我将不胜感激: 1. component: Component 2. const {path, match, ...rest} = props;和 3.
  • 1,2 是对象破坏和剩余参数的概念。在一个中,您从对象中解构并为其分配不同的变量名称。其次是其余扩展语法,其中 ...rest 表示道具中的所有其余元素。在第三种情况下,我们实际上将所有其余参数传递给 Route 组件。请参阅 MDN 以获取 RestObject Destructuring 此处
  • 感谢您的帮助。我仍在尝试理解这些线条。我学起来真的很慢,并且在理解文档方面遇到了很多麻烦。我的速度比赏金期允许的要慢,所以我已经给出了分数,当我解决这个问题时我会回来接受这个答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-09
  • 2015-11-09
  • 2017-06-28
  • 2017-12-31
相关资源
最近更新 更多