安装:
npm i react-router-dom@4.3.1
在 index.js
引入相关模块,并设定好 BrowserRouter
:
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom'; // 路由相关模块
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
registerServiceWorker();
设置基础路由
现在 App
组件是 BrowserRouter
的子组件,我们到 App.js
设置相关的路由:
// App.js
import React, { Component } from "react";
import { Route } from 'react-router-dom'; // 路由相关模块
import Products from "./components/products";
import Posts from "./components/posts";
import Home from "./components/home";
import Dashboard from "./components/admin/dashboard";
class App extends Component {
render() {
return (
<div>
<Route path='/products' component={Products}/>
<Route path='/posts' component={Posts}/>
<Route path='/dashboard' component={Dashboard}/>
<Route path='/' component={Home}/>
</div>
);
}
}
export default App;
我们有 Products
,Posts
,Home
, Dashboard
四个组件,分别对应各自匹配的路由规则。
Route
组件中 path
参数表示 URL 的匹配规则,component
参数表示对应渲染的组件。
如:访问 /products
的 URL 时会渲染 Products
组件。
路由匹配规则
以上路由会出现一个 URL 同时符合多个匹配规则的问题,比如访问 /products
时,会同时匹配到 /
对应的 Home
和 /products
对应的 Products
。如何让解决这个问题呢?
首先路由的算法是检测 URL 是否以给定规则为开头,比如: /products
这个规则,既能匹配到 /products
也能匹配到 /products/abc
。
要解决该问题的第一个方法是使用 exact
属性:
<Route path='/products' component={Products}/>
<Route path='/posts' component={Posts}/>
<Route path='/dashboard' component={Dashboard}/>
<Route path='/' exact component={Home}/>
使用 exact
属性后 /
规则只匹配 URL 为 /
的情况。
第二种方法是使用 Switch
组件:
import { Route, Switch } from 'react-router-dom';
<Switch>
<Route path='/products' component={Products}/>
<Route path='/posts' component={Posts}/>
<Route path='/dashboard' component={Dashboard}/>
<Route path='/' component={Home}/>
</Switch>
Switch
会匹配第一条符合的子规则。所以 Router
的排列需要按照从最特殊到最一般的顺序。
Route 的 Props 属性
我们进入 /products
的 URL 看看渲染出来的 Products
组件有什么属性。
可以看到有 history
,location
,match
三个属性。这三个属性是 Route
为 Products
添加的。(这三个属性的作用详细看官方文档:https://reacttraining.com/react-router/web/api/Route/route-props)
history
记录了浏览器的访问记录,可以实现页面退回等功能。location
记录的是当前页面。match
记录 URL 匹配规则。
添加额外的 Props 属性
现在我要为 Products
加入一个 sortBy
属性,我们使用 Route
的 render
参数配合箭头函数来操作:
{/* 使用箭头函数传递参数,记得要把原来的 props 参数也传入 */}
<Route
path='/products'
render={(props) => <Products sortBy='newest' {...props} />}
/>
现在 Products
属性除了自带的三个属性外还有了我们新增的 sortBy
属性。
通过 URL 传递参数
假设我们引入 ProductDetails
组件来渲染某个 product
,我们使用 id
来作为区分每个 product
的依据。
在 Route
的 path
参数中使用冒号来表示 URL 参数:
<Route path='/products/:id' component={ProductDetails}/>
<Route
path='/products'
render={(props) => <Products sortBy='newest' {...props} />}
/>
这里需要注意 Route
是从上往下只要匹配第一条符合规则的原则,所以更为特殊的规则:/products/:id
应当放在更一般的规则 /products
上方。
那么现在我们可以在 ProductDetails
读取来自 URL 的参数 id
。它在 this.props.match.params.id
里面。
可选的 URL 参数
在 Route 的 path 参数中使用问号来表示可选的 URL 参数:
<Route path='/posts/:month?/:year?' component={Posts}/>
现在 month
和 year
两个参数均为可选。参数存放于 this.props.match.params
中。
get 方法传递参数
HTTP 的 GET 方法允许我们通过 URL 传递参数,例如:/posts?year=2019&month=06
。像 ?year=2019&month=06
这种方法又叫查询字符串。
它们存放在 props.loaction.search
中。
手动读取这个查询字符集比较麻烦,我们安装 query-string
包来帮助我们更方便地去处理这些参数。
npm i query-string@6.1.0
使用方法:
import queryString from 'query-string';
const result = queryString.parse(this.props.location.search);
console.log(result);
// {month: "06", year: "2019"}
注意,转换的结果都是字符串,如果有需要请转会成对应的数据类型。
重定向
使用 Redirect
组件来重定向网页,我们把该组件放在最下方,当所有匹配规则都查找过一遍都没有符合的时候网页就会被重定向到 /not-found
页面。
import {
Route,
Switch,
Redirect } from 'react-router-dom';
……………………
<Route path='/not-found' component={NotFound} />
<Route path='/' exact component={Home}/>
<Redirect to='/not-found' />
Redirect
组件有 from
和 to
两个属性,可以定义从哪个页面跳转到指定页面的功能。
<Redirect from='/messages' to='/posts' />
当访问 /message
页面时候就会被跳转到 /posts
。