【青训营】- React-Router (极简实践指南)

640 阅读2分钟

前言

本文主要介绍react-router一种实践方案,可以提供一种路由可配置路由权限管理的实现思路。可以在codesandbox查看完成代码。

总结:

  1. 在react-router 中一切皆组件, 则 BrowserRouterHashRouter 分别来实现history路由与hash路由.
  2. Link 组件 用于修改 url, Route 组件 则用于展示 url 对应的组件
  3. path路径 匹配方式采用 path-to-regexp 库, 将字符串形式的 path 转换为一个正则表达式,然后将它与当前的位置进行匹配
  4. 导航方式有 声明式Link 和 命令式 useHistory
  5. 参数传递, 可以用 state 或 url 上 query 的方式传参, 注意: state 传参 只在 history 模式下生效.
  6. Route渲染优先级:children > component > render, 其中render属性 是实现 路由拦截 的核心.

配置文件样例:

/**
author: 表示需要权限才能访问的路由
hide: 表示在菜单中不展示
root: 表示是只在第一层渲染
*/
const ROUTE_CONFIG = [
  {
    path: '/',
    exact: 'true',
    component: Home
  },
  {
    path: '/list',
    component: List,
    author: true,
    routes: [
      {
        path: '/list/detail',
        author: true,
        component: Detail
      }
    ]
  },
  ....
  {
    path: '/login',
    hide: true,
    root: true,
    component: Login
  },
  {
    path: '*',
    hide: true,
    root: true,
    component: NotFoundPage
  }
]

Menu实现

核心原理: 递归


/* hide 则不展示 */

function Menu({ routes }) {
  return <ul>
    {routes.map((item) => {
      return item.hide ?
        null :
        <React.Fragment key={item.path}>
          <MenuItem {...item} />
        </React.Fragment>
    })}
  </ul>
}

function MenuItem({ path, component, routes, hide }) {
  return hide ?
    null :
    (<li>
      <Link to={path}>{component.name}</Link>
      {routes?.length && <Menu routes={routes}></Menu>}
    </li>)
}

RouterPage实现

通过递归, 实现嵌套路由


/* 
    author表示需要登录才能访问  
    root + level 实现只在第一层渲染
*/

function RouterPage({ routes, level = 0 }) {
  const { auth } = useContext(AuthContext)
  if (routes?.length) {
    return <>
      <Switch>
        {
          routes.map((item, i) => {
            if (item.root && !level) {
              return <Route path={item.path} exact={!!item.exact} key={i} component={item.component} />
            }
            return <Route path={item.path} exact={!!item.exact} key={i} render={() => {
              return (auth || !item.author) ?
                <>
                  <item.component />
                  <RouterPage routes={item.routes} level={level + 1} />
                </> :
                <Redirect to={{ pathname: '/login', state: { redirect: item.path } }} />
            }} />
          })
        }
      </Switch>
    </>
  }
  return null
}

权限采用ContextAPI实现

核心API: React.createContext, React.useContext

ContextAPI 使用心得:

  • React.createContext 的value属性类 似于 父组件的props派发数据
  • React.useContext 就类似于从props中获取数据

const AuthContext = React.createContext()

const AuthRouterPage = () => {
  const [auth, setAuth] = useState(false)
  return <AuthContext.Provider value={{ auth, login: () => setAuth(true) }}>
    <BrowserRouter >
      {auth ?
        <>
          <h1>
            <mark>User: Admin<button onClick={() => setAuth(false)}>logout</button></mark></h1>
        </> :
        null
      }
      <Menu routes={ROUTE_CONFIG}></Menu>
      <RouterPage routes={ROUTE_CONFIG} />
    </BrowserRouter>
  </AuthContext.Provider>
}

参考: