可以参看官方github里面的文档。
官方github地址:https://github.com/ReactTraining/react-router
往下翻到如图所示位置,然后选择对应版本的API Docs
一、react-router的安装和使用
1、react-router的安装
安装命令:
npm install react-router-dom --save
引入:
import { BrowserRouter as Router,Switch,Route,Link } from "react-router-dom";
2、react-router的使用
使用<Router></Router>标签包裹,在里面使用<Route></Route>:
<Router>
<div>
<Link to="/">首页</Link><br/>
<Link to="/tool">工具</Link>
<hr/>
<Route exact path="/">
<Index/>
</Route>
<Route path="/tool">
<Tool/>
</Route>
{/* <Route exact path="/" component={Index}/>
<Route path="/tool" component={Tool}/> */}
</div>
</Router>
如上面的例子<Route />的两种写法都可以:
//第一种写法
<Route path="/tool">
<Tool/>
</Route>
//第二种写法
<Route path="/tool" component={Tool}/>
Route中的exact属性:表示严格匹配,一般来说,react路由会匹配所有匹配到的路由组件,exact能够使得路由的匹配更严格一些。
exact的值为bool型,为true是表示严格匹配,为false时为正常匹配。
<Route path='/' component={Index} />
<Route path='/tool' component={Tool}>
//这种情况下,如果匹配路由path='/tool',那么会把Index组件也会展示出来。
<Route exact path='/' component={Index} />
<Route path='/tool' component={Tool} />
//添加exact后,path='/',则会显示Index组件;
path='/tool',则只会显示Tool组件,不会显示Index组件
3、<Redirect />重定向跳转
render(){
if(this.state.flag){
return <Redirect to={{pathname:"/selectCity"}} />
}
return(
);
}
当this.state.flag为true时,通过<Redirect />标签来实现跳转,标签中的to属性为要跳转到哪里,pathname就是要跳转的路径。
二、动态路由及get传值
一个页面跳转到另外一个页面进行传值:get传值、动态路由、LocalStorage
1、动态路由传值
动态路由就是在匹配路径path的后面加上冒号+参数,如path="/info/:id"。用一个共同的信息组件,根据不同的需要动态渲染不同的内容。
- 先需要导入模块
import { BrowserRouter as Router,Switch,Route,Link } from "react-router-dom";
- 动态路由标签
需要用<Router></Router>标签包裹起来作为根标签,在标签中使用<Link />、<Route />和<Switch />标签。 - 动态路由的使用
RouterIndex.js
import React from 'react';
//引入模块
import { BrowserRouter as Router,Switch,Route,Link } from "react-router-dom";
//引入组件
import Product from './Product';
import Info from './Info';
import Index from './Index';
class RouterIndex extends React.Component {
constructor(props) {
super(props);
this.state = { };
}
render() {
return (
<Router>
<div>
<Link to="/">index页面</Link>
<Link to="/product">Product页面</Link>
<hr/>
<Switch>
<Route exact path="/" component={Index} />
<Route path="/product" component={Product} />
</Switch>
//Info页面根据需要看写在哪
{/* <Route path="/info/:aid" component={Info} /> */}
</div>
</Router>
);
}
}
export default RouterIndex;
<Link>标签:
配置路由,这里需要注意<Link>标签的L是大写的,这是react-router中的,写错会报错。
<Link to="/product">Product页面</Link>
标签中的to="/product"这个是指向下面配置的路由路径,和<Route>中的path中的路径相对应。
<Route>标签:
<Route exact path="/" component={Index} />
标签中的path和上面<Link>标签中to里面的路径对应,
component是配置要跳转到的组件
我们在<Route>标签中看到有个exact属性,关于这个要和<Switch>标签一起讲。我们在使用时不使用<Switch>标签也是可以的。
exact是:精准匹配,意思就是当url和该<Route>标签中的path属性进行精确比对后,完全相同才会被渲染。
<Switch>是:渲染第一个被location匹配到的并且作为子元素的<Route>或者<Redirect>。
关于<Switch>的坑
如果只是用这个标签不添加exact属性的话,当path="/product"的时候只会显示index页面。所以需要的话还需要配上exact属性使用。
对于不加<Switch>和exact的话,对于上面代码中的路由:
如果使用path="/",则会显示index页面;
如果使用path="/product",则会显示index页面和product页面;
Product.js
import React from 'react';
import { BrowserRouter as Router,Switch,Route,Link } from 'react-router-dom';
import Info from './Info';
class Product extends React.Component {
constructor(props) {
super(props);
this.state = {
list:[{id:'1',info:'aaa'},{id:'2',info:'bbb'},{id:'3',info:'ccc'}]
};
}
render() {
return (
<Router>
<div>
<ul>
{this.state.list.map((value,key)=>{
return(
<li key={key}>
<Link to={`/info/${value.id}`}>info:{value.info}</Link>
</li>
)
})}
</ul>
<Route path="/info/:id" component={Info} />
</div>
</Router>
);
}
}
export default Product;
在projuct页面模拟产品数据,然后使用map方法遍历出来,遍历后我们需要给它们添加上Link,然后可以点击路由到产品信息Info页面。
<Link to={`/info/${value.id}`}>info:{value.info}</Link>
标签上to的值除了路径,还需要添加上要携带的参数
在写法上如代码所示{`/路径/${值}`}:特殊符号是英文状态esc下面的那个键
我们需要在<Link>对应的路由的path上也是这种路径+参数的格式,如下:
<Route path="/info/:id" component={Info} />
这里我们只需要路径+冒号+加参数名字即可
当路由到Info页面后,传的值其实存在props里面:
Info.js
<span>收到传值--->id:{this.props.match.params.id}</span>
传的值保存在props下的match下的params里面,我们直接获取即可
2、动态路由get传值
因为我们获取到的参数是这样的http://localhost:3000/info?id=2,获取的结果是?id=2,我们可以自己使用js对参数进行解析,这里介绍个模块来进行解析。
- 安装url模块:
cnpm install url --save
import url from 'url';//引入url模块
- 使用
<Route path="/info" component={Info} />
<Link to={`/info?id=${value.id}`}></Link>
如上写法
在页面上我们还是需要在props里面获取值:
this.props.location.search
获取的结果:?id=2
我们可以使用url模块对齐进行解析:
url.parse(this.props.location.search,true)
第二个参数传入true,则是 query:{id: "2"} 的格式,接下来我们获取id值:
var query = url.parse(this.props.location.search,true).query;
var id = query.id //获取到id值
需要注意的是:我们在componentDidMount里完成对数据的请求时,这个时候会在componentDidMount之前渲染,对于<img/>标签来说,这个时候的路径是不存在的,这个时候会有404,所以我们需要先判断:
如果存在img_url就使用标签,如果不存在就返回""
{this.state.list.img_url?<img src={`${this.state.domain}${this.state.list.img_url}`} />:""}
三、嵌套路由及传值
实现如上图效果,左侧的main、info和右侧的内容显示在同一个组件中布局,先来个简单的例子,下面是代码:
export default class QtRouter extends React.Component {
constructor(props){
super(props);
this.state = {
status:1
}
}
setBtnStyle=(num)=>{
console.log("setBtnStyle方法执行");
this.setState({
status:num
});
}
render() {
return(
<div className="user">
<div className="content">
<div className="left">
<Button type={1 === this.state.status ? "primary" : ""} onClick={this.setBtnStyle.bind(this,1)}><Link to="/qtRouter/">main</Link></Button><br/><br/>
<Button type={2 === this.state.status ? "primary" : ""} onClick={this.setBtnStyle.bind(this,2)}><Link to="/qtRouter/info">info</Link></Button>
</div>
<div className="right">
<Route exact path="/qtRouter/" component={Main}/>
<Route path="/qtRouter/info" component={Info}/>
</div>
</div>
</div>
);
}
}
左侧放<Link/>链接,右侧部分放入<Route/>路由。
上面是简单的嵌套路由的例子,再看下图的例子:
这个导航有两个按钮,分别对应两个页面,个人中心的页面中包含main和info,分别对应两个页面,main和info是个人中心的子路由。
//routes.js
//路由配置文件
import Login from "../components/Login";
import QtRouter from "../components/QtRouter";
import Main from "../components/qtRouterComponent/Main";
import UseInfo from "../components/qtRouterComponent/UseInfo";
const routes = [
//登录的route配置
{path:"/login",component:Login},
//个人中心的route配置
{path:"/qtRouter",component:QtRouter,
routes:[
{path:"/qtRouter",component:Main,exact:true},
{path:"/qtRouter/userInfo",component:UseInfo}
]
}
];
export default indexRouteConfig;
上面是路由的配置routes.js,相当于之前的<Route path="/path" component="/component"/>里面path和component的值。这个文件上方需要导入用到的组件。
//CommonRoute.js
import React from 'react';
import { Route } from "react-router-dom";
export default function CommonRoute (route){
if (route.exact) {
return (
<Route exact path={route.path} render={props=>(
//此处给子路由传值{...props}
<route.component {...props} routes={route.routes} />
)} />
);
}else{
return (
<Route path={route.path} render={props=>(
<route.component {...props} routes={route.routes} />
)} />
);
}
}
上面是一个公共的路由组件,这个函数接收的值(route)中包含了上面routes.js的内容,这个函数组件作用相当于是渲染成<Route path="/path" component="/component"/>,如demo中注释处给子路由传值。
在写法上使用了render,此写法相当于是component="/component,关于render的写法如下所示:
render={props=>(
<route.component {...props} routes={route.routes} />
)
下面是登录和个人中心的组件:
//RouterIndex.js
import React, { Component } from 'react';
import { BrowserRouter as Router,Link } from "react-router-dom";
import routes from '../router/routes';
import CommonRoute from './CommonRoute';
export default class RouterIndex extends Component {
constructor(props) {
super(props);
this.state = { };
}
render() {
return (
<Router>
<Link to="/login">登录</Link>
<Link to="/qtRouter">个人中心</Link>
<hr/>
{
routes.map((route,key)=>{
return <CommonRoute key={key} {...route} />
})
}
</Router>
);
}
}
此组件中导入我们写的公共路由组件CommonRoute.js和路由配置routes.js,接下来使用map遍历routes获取值,通过公共路由组件来渲染<Route/>:
{
//遍历routes中的数据
routes.map((route,key)=>{
//使用CommonRoute公共组件,将route值传入,即{...route}
return <CommonRoute key={key} {...route} />
})
}
下面是main和info组件的demo:
//QtRouter .js
import React from 'react';
import { Link } from "react-router-dom";
import CommonRoute from './CommonRoute';
export default class QtRouter extends React.Component {
constructor(props){
super(props);
this.state = { }
}
render() {
return(
<Router>
<Link to="/qtRouter">main</Link>
<Link to="/qtRouter/userInfo">info</Link>
{
//我们使用this.props.routes来获取配置文件routes.js中子路由的数据
this.props.routes.map((route,key)=>{
return <CommonRoute key={key} {...route} />
})
}
</Router>
);
}
}
我们使用this.props来获取传入的数据,数据是保存在this.props中的。
如果不抽离公共路由组件CommonRoute.js的话,在页面组件中就可以直接使用公共路由组件的方法。
写在最后:
- 如果文章中有错误或是表达不准确的地方,欢迎大家评论中指正,以便我完善。
- 文章我也会根据所学到新的知识不断更新。
网友评论