如何优雅的使用react router v6, 并实现全局守卫
前言
哈喽大家好,我是Charlie,最近想把react补起来,总觉得只有Vue出门没安全感,更不好意思说自己是个前端攻城狮,所以抽空开始把react搞起来,今天给大家分享最近的心得和其中一些操作,对啦,最近发现react的官网也更新了,旧的官网,新版中文官网,同时建议大家有空多看看原版英文官网,废话不多说,开干!!!
1.项目初始化
首先用一句话简单总结下react是什么? React 是一个用于构建用户界面的 JavaScript 库 对于项目初始化这话,react也有自己的脚手架Create React App,react官网也是建议我们初学者使用CRA去初始化一个react项目,奈何这个这个脚手架太鸡肋,好多东西都需要开发者手动去配置,另外是基于webpack的,所以项目大的时候配置起来是及其麻烦,那怎么办呢? 还好有尤大的vite,vite也支持快速生成react项目,并内置一些基础配置,使用起来是真香 套用几句vite官网的介绍:
- 一个开发服务器,它基于 原生 ES 模块 提供了 丰富的内建功能,如速度快到惊人的 模块热更新(HMR)。
- 一套构建指令,它使用 Rollup 打包你的代码,并且它是预配置的,可输出用于生产环境的高度优化过的静态资源。
pnpm create vite
我们取名为react-ts,然后选择react技术栈,以及TypeScript语言
ok,项目初始化完毕后,我们运行如下,标识已经初始化成功!
2.react-router v6简单介绍
react router 发布了三个不同的包:
- react-router:路由核心库,提供许多组件、钩子;
- react-router-dom: 包括了 react-router 所有内容,同时添加了用于 DOM 的组件,如
<BrowserRouter>
; - react-router-native: 包括了 react-router 所有内容,同时添加了用于 ReactNative 的 API,如
<NativeRouter>
。
与react-router 5.X区别:
- 内置组件的变化:移除
<Switch/>
,新增<Routes/>
…… - 语法变化:
component={About}
变成element={<About/>}
…… - 新增 hook:
useParams
、useNavigate
、useMatch
…… - 官方明确表示推荐使用函数式组件
3.使用react route v6创建路由表
首先我们先安装react router v6以及依赖
pnpm install react-router router-router-dom
安装完路由后,我们也想使用vue那样,单独创建一个路由表,用来管理路由。
#依次执行下面代码
cd src
mkdir routes
touch index.tsx
我们首先创建两个页面,一个home页面,一个about页面,然后再routes/index.tsx中引入,那是否可以像vue那样实现路由懒加载呢,答案是当然可以,react也为我们光大开发者提供了一个懒加载的api,就是React.lazy(),通过这个方法,我们就可以实现路由懒加载
const Home = React.lazy(() => import('../pages/Home'))
const About = React.lazy(() => import('../pages/About'))
interface Route {
path: string,
name: string,
element: ReactNode
}
export const routes: Route[] = [
{
path: '/home',
name: 'home',
element: <Home />
},
{
path: '/about',
name: 'about',
element: <About />
},
]
ok 路由表建立后我们如何在页面中优雅的展示呢? 这里不得不提useRoutes这个hooks, 他能够将我们创建的路由表一一映射成为路由对象 我们也想vue开发中一样,在App.tsx中引入刚才我们创建好的路由表,
function App() {
const elements = useRoutes(generateRouter(routes))
return (
<div>
{elements}
</div>
)
}
这样一个简单的路由表就创建好了,但是开发中,我们肯定不会是这么简单,比如,切换路由时我们可以增加loading转场等,react也为我们提供了React.Suspense组件,通过callback props传入一个loading,来实现转场效果,我们用该组件将上面的elements封装下
<React.Suspense fallback={<Loading/>}>
{elements}
</React.Suspense>
封装完后,在切换路由时,会发现有一个loading转场的一个效果。
4.增加全局守卫
如果是一个大型项目,那简单的路由表肯定是不能满足我们的需求的,比如常见的权限校验,前置逻辑等等就无法处理。那react-router没有像vue一样的类似全局守卫的函数吗? 那还真没有,不得不说react是真的优秀,什么都需要自己手动去搞定,搞就搞,谁怕谁,哈哈哈哈 无非我们就是实现一个高阶组件包裹下,然后再高阶组件里面我们去做下路由拦截处理和前置逻辑处理 我们首先对刚才的路由表进行扩展,我们先增加一个权限校验和子组件吧
interface Route {
path: string,
name: string,
element: ReactNode,
children?: Route[],
auth?: boolean
}
export const routes: Route[] = [
{
path: '/home',
name: 'home',
element: <Home />
auth: true
},
{
path: '/about',
name: 'about',
element: <About />
},
]
紧接着需要对上面的路由表实现一个类似中间件的映射,首先实现一个RouterBeforeEach
高阶组件,参数为外部传入的routes,在该组件内部,将上面我们写的routes和传入的做一个对比和判断,如果有auth并且为true,则需要做权限校验,如果没有,则不需要。
export const RouterBeforeEach = ({children}: any) => {
const location = useLocation();
const navigator =useNavigate()
useEffect(() => {
let router = getCurrentRouterMap(routes, location.pathname)
if(!isLogin && router.auth) {
navigator('/login')
}
}, [location.pathname]);
return children
}
另外上面的两个hooks:
- useLocation: 这个钩子返回当前路由对象。如果您想在当前路由更改时执行一些副作用,我们就可以使用这个hooks。
- useNavigate: useNavigate钩子返回一个函数,这个hooks能够让我可以编程式的导航。
上面的getCurrentRouterMap就是在路由表中获取到当前的路由对应的路由
const getCurrentRouterMap = (routers: Router[], path: string): Route => {
for(let router of routers) {
if(router.path == path) return router;
if(router.child) {
const childRouter = getCurrentRouterMap(router.child, path)
if(childRouter) return childRouter;
}
}
return routes[routes.length -1]
}
然后,我们在去App.tsx中用RouterBeforeEach包裹下elements
<React.Suspense fallback={<Loading/>}>
<RouterBeforeEach>
{elements}
</RouterBeforeEach>
</React.Suspense>
</div>
ok,到这里用react-router 6实现一个路由表,并实现一个全局守卫已经完成。
5.总结
总的来说,react对初学者确实比vue要要求高些,很多东西需要自己手动去封装和处理,不像vue,在框架层面已经帮我们做了太多的处理,对开发者还是非常友好的;但是不能说react就不友好,只能说各有各的好处,相信坚持下去他会给我们能力上带来很大的提升。 好了,喜欢的小伙伴赶紧手动实践起来吧。
转载自:https://juejin.cn/post/7222787944297791543