React Router 是一个基于 React 之上的路由库,它可以让你向应用中快速地添加视图和数据流,同时保持页面与 URL 间的同步。
React Router 是建立在 history 库之上的。 history 监听浏览器地址栏的变化,解析 URL 并转化为 location 对象, 然后 router 使用它匹配到路由,最后正确地渲染对应的组件。
该文章写于 2021-11-29 10:56:40 目前 React-router 最新版本为 6.0.2,React-router 不同版本 API 相差较大,该文章以当前最新版本为标准。
React router 用法
1 | import React from "react"; |
- 根结点 BrowserRouter 表示采用浏览器 path 导航
- Routes 是 Route 的父节点,表明从子节点 Route 中选一个匹配,Route 的 path 参数表明对应的路由路径,element 参数表明需要渲染的组件
- Route 可以嵌套,当 Route 嵌套时,父组件中的 Outlet 组件表明了子组件渲染的位置
- Route 的 index 参数为 true 表示其为当兄弟 Route 的 path 均不匹配时的默认渲染组件
- path 参数’*’为通配符,以 ‘/‘开头时为绝对路径,否则为相对路径
- Navigate 表示跳转到对应路径,replace 参数代表是否替换当前 history,所以其实实现了重定向的功能
1
2
3<Route path="old-expenses" element={
<Navigate to="/expenses" replace />
}>
1 | import { Outlet, Link } from "react-router-dom"; |
- Link 表示点击跳转(渲染为a元素),to 参数表示跳转的路径
- Outlet 标志了子组件的渲染位置
1 | import { NavLink, Outlet, useSearchParams } from "react-router-dom"; |
- 通过 useSearchParams 钩子可以获取到搜索参数
- NavLink 同 Link 类似,也会渲染成 a 元素,但是 style 属性和 className 属性中提供了 isActive 参数来识别是否和当前页面一致
- NavLink 比较跳转链接和当前页面地址是否一致时只比较页面路径,如果还需比较其他参数,可以通过 useLocation 钩子获取 location 相关的参数自行比较
1 | import { useParams, useNavigate } from "react-router-dom"; |
- 通过 useNavigate 钩子可以实现程序控制的跳转/重定向(添加第二个参数
{ replace: true }
) - 通过 useParams 钩子可以获取页面 path 参数,该参数为字符串类型
常用API
Packages 包
React router 包含了三个 npm 库 react-router、react-router-dom 和 react-router-native。
react-router 库包含了最核心的组件和钩子
react-router-dom 库包含了 react-router 库和一些 DOM 操作相关的API 例如
<BroserRouter>
<HashRouter>
<Link>
react-router-native 库包含了 react-router 库和一些和 RN 相关的API 例如
<NativeRouter>
和 本地版本的<Link>
Setup 开始
你必须在组件树的根结点使用一个 router 组件才能在应用中使用 React router。根据应用类型的不同,React router 提供了几种不同的 router 。
<BrowserRouter>
和<HashRouter>
应当在 web 浏览器环境中使用,其中<BrowserRouter>
采用浏览器 path 导航,体验更好,而<HashRouter>
采用 hash 导航,兼容性更好。<StaticRouter>
在服务器渲染的时候使用。<NativeRouter>
在 React Native 应用中使用。<MemoryRouter>
在测试场景中使用。
Routing 路由
路由决定了当你给定应用的页面时,哪一个React组件应当被渲染以及如何嵌套。React router 提供了两种接口描述路由。
- 使用JSX的话可以用
<Routes>
和<Route>
- 使用Js配置的话,可以用
useRoutes
Navigation 导航
React router 的导航接口允许通过修改当前 location 来改变当前渲染的页面。
<Link>
和<NavLink>
生成一个<a>
元素,当用户点击时进行相应的导航。<NavLink>
的style
和className
属性提供了isActive
参数来判断 Link 是否是当前页面地址useNavigate
和<Navigate>
允许程序性的导航,尤其是在事件处理器中或者状态变化时
Hooks 钩子
useSearchParams
钩子可以获取到 URL 的搜索参数useLocation
钩子可以获取到当前的 history.location 参数useParams
钩子可以获取到 path 传递的参数useRoutes
钩子是<Routes>
的函数形式useNavigate
钩子返回 navigate 函数,允许程序性的导航
History
React router 底层使用到了 history 库。 history 库抽象表示了浏览历史的变化,它监听浏览器地址栏(页面路由)的变化,并解析 URL 将其转化为 locaton 对象。基于环境和实现方式的不同,history 库提供了三种形式的 history:
- browserHistory: 通过 HTML5 提供的 history API 实现,需要配置服务器路由将请求重定向到html文件,对应 React router 的
BrowserRouter
例如在 nodejs 中需要配置
1 | app.get('*', function (request, response){ |
如果使用的 nginx 服务器,则需要配置
1 | server { |
如果使用的 Apache 服务器,则需要配置
1 | RewriteBase / |
- hashHistory: 通过 hash(#) 来实现,不支持 history API 的老旧浏览器也可使用,对应 React router 的
HashRouter
- memoryHisotry: 路由存储在内存里,url不会变化,因此不能通过url分享,通常在 node , React Native 环境下使用,对应 React router 的
MemoryRouter
React router 和 Redux 集成
React router 可以和状态管理库 Redux 集成,以便将路由信息同步到 Redux state 统一管理,并且路由组件可以从 Redux 获取路由信息,实现导航等功能。
集成好处:
- 路由信息可以同步到统一的 store 并可以从中获得
- 可以使用 Redux 的 dispatch action 来导航
- 集成 Redux 可以支持在 Redux devtools 中路由改变的时间履行调试
方法:用 react-redux 的<Provider store={store}>
包住 react-router 的路由组件<Router>
、<BrowserRouter>
1 | ReactDOM.render( |
代码分割
React router 可以结合 webpack 和 @babel/plugin-syntax-dynamic-import、loadable-components 来实现代码分割。
一个 React router + webpack + @babel/plugin-syntax-dynamic-import + loadable-components 实现代码分割的简单示例:
.babelrc 配置文件:
1 | { |
@babel/plugin-syntax-dynamic-import 插件避免 babel 对动态 import 语法做过多的转化,允许 webpack 打包时将动态 import 的代码分离成单独的 bundle,实现代码分割。
使用 loadable-component 和动态 import 懒下载组件:
1 | import loadable from "@loadable/component"; |
react-router & react-router-dom 关系
react-router 只是一个核心库,在具体使用时应该基于不同的平台要使用不同的绑定库。比如:我们要在浏览器中使用 React router,就安装 react-router-dom 库,如果在 React Native 中使用 React router 就应该安装 react-router-native 库。但是我们不需要直接安装 react-router 库。