react-router 通过管理 URL,实现组件的切换和状态变化。
基本用法
React Router 的安装命令:
npm install --save react-router
// 或者
yarn add react-router
使用方式:
import React from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
function Index() {
return Home
;
}
function About() {
return About
;
}
function Users() {
return Users
;
}
function AppRouter() {
return (
);
}
export default AppRouter;
上述示例中:
-
Router
组件本身只是一个容器,真正的路由需要通过Route
组件定义 -
Route
组件中,path
属性是指跳转的url
,component
属性用来定义跳转到的页面组件
注意:
path
只需要配置 URL 中的路径就行,不需要理会请求参数部分。如,你的路由配置如下:
那么以下 URL 均匹配到这个路由配置,显示
ListPage
:
- /list
- /list?searchText=react
- /list?searchText=react&beginTime=20180101&endTime=20190530
嵌套路由
import React from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
// App组件中定义根路由
function App() {
return (
);
}
function Home() {
return Home
;
}
function About() {
return About
;
}
function Topic({ match }) {
return Requested Param: {match.params.id}
;
}
// 在Topics组件中定义子路由
function Topics({ match }) {
return (
Topics
-
Components
-
Props v. State
Please select a topic.
}
/>
);
}
function Header() {
return (
-
Home
-
About
-
Topics
);
}
export default App;
上述示例是在 Topics 组件中嵌套了子路由:
- 在
Topics
组件中,传入一个match
对象属性,然后我们继续在 Topics 组件定义 Link 在路径to={
${match.url}/components}
其中match.url
返回的就是/topics
,这个跳转路径实际为/topics/components
。 - 在 Topics 组件中定义
${match.path}/:id} component={Topic} />,这里的 id 对应 ${match.url}/components}>Components中的 components
。 - 其中
${match.path}/:id} component={Topic} />就是 的子路由。
Route 组件
Route
是用于声明路由映射到应用程序的组件层。Route
有两个特别重要的属性:path
和component
,其中path
指定路由匹配的路径(url);component
定义路由对应的页面组件。
import { Route } from 'react-router-dom';
const About = () => About;
// 当路径匹配到`/about`时,会渲染About组件
;
其它属性
-
exact
完全匹配,路径必须完全一致,才能渲染对应页面
// 路径必须为`/about`时才能渲染About,如果为`/about/:id`则不渲染 -
strict
严格匹配。如果为
true
,则具有尾部斜杠的路径将仅匹配具有尾部斜杠的location.pathname
。当location.pathname
中有其他 URL 段时,这不起作用。 -
sensitive
是否需要区分大小写,如果为 true,则在匹配路径时会区分大小写。
// 路径必须为`/about`时才能渲染About,如果为`/About`则不渲染
Switch
Switch
组件将迭代其所有子元素,并且仅渲染与当前位置匹配的第一个子元素,避免重复渲染。
-
ContactUs
此时只会渲染一个 ContactUs 组件,而不是重复渲染两次。
Router
Router
能够保持 UI 和 URL 的同步。
属性
-
children
一个或多个
Route
。当history
改变时,Router
会匹配出Route
的一个分支,并且渲染这个分支中配置的组件,渲染时保持父route
组件中嵌套的子route
组件。 -
history
Router
监听的history
对象
页面跳转
这里我们简单介绍两种页面跳转方式:Link
、push
、goBack
等方法调用。
Link
允许路由跳转的主要方式。以适当的href
去渲染匹配到的路由组件。可以接收到Router
的状态。
About // 点击渲染`/about`匹配到的页面
上述示例,当我们点击时,URL
会更新,组件会被重新渲染。其中,to
指定链接到的路径。
to
不仅可以是字符串,还可以 location 是对象。
除此之外,Link
的replace
属性如果为 true,则单击该链接将替换历史堆栈中的当前条目,而不是添加新条目。
//此时历史堆栈中的当前条目会被替换
调用方法
history.push()
import React from 'react';
import { withRouter } from 'react-router';
function Button() {
const { history } = props;
return ;
}
export default withRouter(Button);
点击Button
,页面将会渲染/about
路径匹配到的组件
history.goBack()
import React from 'react';
import { withRouter } from 'react-router';
function Button() {
const { history } = props;
return ;
}
export default withRouter(Button);
点击按钮,页面将会回退,渲染前一个组件。
附: 重定向(Redirect)
import { Route, Redirect } from 'react-router';
(loggedIn ? : )}
/>;
上述示例中,如果路由匹配到/
时,loggedIn
为true
时,路由就会重定向至/dashboard
。
上述示例,当路由匹配到/old-path
时,会被重定向到/new-path
,渲染Place
组件。
数据传递
页面之间通过路由参数进行数据交互主要有三种方式:
- 路径参数
- 请求参数
history state
1. 路径参数
用于传递数据的 id。注意不要因为需要传递一些查询条件等临时数据,不要使用路径参数,而是使用下一节介绍的请求参数。
//通过路由传递gwlx和recordId参数
// HelloWorldPage.tsx中参数获取
import { withRouter } from 'react-router';
function HelloWorldPage(props){
const {gwlxId,recordId} = props.match.params;
return (<>
公文类型为:{gwlxId}
数据ID为:{recordId}
>)
}
export default withRouter(HelloWorldPage);
2. 请求参数
请求参数可以用来传递除数据 id 之外的数据。如查询条件。
首先看一下一个普通的 URL:
/archive/dispatch-list?userId=123&userName=张三
其中
/archive/dispatch-list
是路径部分,而?userId=123&userName=张三
是查询参数,也称之为请求参数。我们可以通过
location.search
获取到查询参数。可以使用qs
模块解析查询参数。const searchParams = qs.parse( props.location.search ? props.location.search.substr(1) : '', );
在创建这样的 URL 时,也可以用
qs
模块格式化请求参数:const searchParams = { userId: '123', userName: '张三' }; const url = `/archive/dispatch-list?${qs.stringify(searchParams)}`;
// Button.tsx
import { withRouter } from 'react-router';
function Button(props) {
return (
);
}
export default withRouter(Button);
// HelloWorldPage.tsx中参数获取
import { withRouter } from 'react-router';
import qs from 'qs';
function HelloWorldPage(props) {
const { userId, userName } = qs.parse(
props.location.search ? props.location.search.substr(1) : '',
);
return (
<>
用户名为:{userName}
用户ID为:{userId}
>
);
}
export default withRouter(HelloWorldPage);
3. history state
使用请求参数可以传递很多数据,但是同时也会污染 URL。有时,我们只想向新页面传递一些临时的数据,又不想让用户在浏览器地址栏上看到非常长的 URL,或者不想让用户收藏这个链接,再次打开这个链接时还带着这些临时数据。如果是这样的情况,我们可以使用history state来传递数据。
请注意:如果是给列表页传递查询条件,使用请求参数。
千万注意:刷新页面或者重新打开页面,不会再有之前的
history state
数据。浏览器的历史回退、前进会保持页面的history state
。
// Button.tsx
import { withRouter } from "react-router";
function Button(props) {
return (
);
}
export default withRouter(Button);
// HelloWorldPage.tsx中参数获取
import { withRouter } from "react-router";
function HelloWorldPage(props) {
const { gwlxId, recordId } = props.location.state || {};
return (
<>
公文类型为:{gwlxId}
数据ID为:{recordId}
>
);
}
export default withRouter(HelloWorldPage);
小结
路径参数和请求参数的方式适合传递少量的数据,history state 适合传递完整的数据对象。
总结
此教程通过描述 react-router 中的基本组件及其简单用法。更多用法请移步至react-router 官网希望我们能够快速掌握路由定义、路由配置、路由跳转、路由传参等相关技能。
参考资料
- react-router 官网
- React Router 4 简易入门
- React Router 中文文档
- React Router 使用教程