安装
输入以下命令进行安装:
# npmnpm install react-router-dom# yarnyarn add react-router-dom
react-router相关标签
react-router常用的组件有以下八个:
import {BrowserRouter,HashRouter,Route,Redirect,Switch,Link,NavLink,withRouter,} from 'react-router-dom'
简单路由跳转
实现一个简单的一级路由跳转
import {BrowserRouter as Router,Route,Link} from 'react-router-dom'import Home from './home'import About from './about'function App() {return (<div className="App"><Router><Link to="/home" className="link">跳转Home页面</Link><Link to="/about" className="link">跳转About页面</Link><Route path="/home" component={Home}/><Route path="/about" component={About}/></Router></div>);}export default App;
效果如下:

要点总结:
Route组件必须在Router组件内部Link组件的to属性的值为点击后跳转的路径Route组建的path属性是与Link标签的to属性匹配的;component属性表示Route组件匹配成功后渲染的组件对象嵌套路由跳转
React的路由匹配层级是有顺序的
例如,在App组件中,设置了两个路由组件的匹配路径,分别是/home和/about,代码如下:import {BrowserRouter as Router,Route,Link,} from 'react-router-dom'import Home from './home'import About from './about'function App() {return (<div className="App"><Router><Link to="/home">跳转Home页面</Link><Link to="/about">跳转About页面</Link><Route path="/home" component={Home}/><Route path="/about" component={About}/></Router></div>);}export default App;
然后
Home组件中同样也想设置两个路由组件的匹配路径,分别是/home/one和/home/two,此时就可以看出,这个/home/one和/home/two为上一级路由/home的二级嵌套路由,代码如下:import React from 'react'import {Route,Link,} from 'react-router-dom'import One from './one'import Two from './two'function Home () {return (<>我是Home页面<Link to="/home/one">跳转到Home/one页面</Link><Link to="/home/two">跳转到Home/two页面</Link><Route path="/home/one" component={One}/><Route path="/home/two" component={Two}/></>)}export default Home
:::danger 特别注意:
Home组件中的路由组件One的二级路由路径匹配必须要写/home/one,而不是/one,不要以为One组件看似在Home组件内就可以简写成/one:::动态链接
NavLink可以将当前处于active状态的链接附加一个active类名,例如:import {BrowserRouter as Router,Route,NavLink} from 'react-router-dom'import Home from './home'import About from './about'function App() {return (<div className="App"><Router><NavLink to="/home" className="link">跳转Home页面</NavLink><NavLink to="/about" className="link">跳转About页面</NavLink><Route path="/home" component={Home}/><Route path="/about" component={About}/></Router></div>);}export default App;
/* 设置active类的样式 */.active {font-weight: blod;color: red;}
路由匹配优化
当点击跳转链接时,会自动去尝试匹配所有的
Route对应的路径,如图所示:
正常情况下,只需匹配到一个规则,渲染即可,即匹配成功一个后,无需进行后续的匹配尝试,此时可以用Switch组件,如下所示:import {BrowserRouter as Router,Route,NavLink,Switch,} from 'react-router-dom'import Home from './home'import About from './about'function App() {return (<div className="App"><Router><NavLink to="/home" className="link">跳转Home页面</NavLink><NavLink to="/about" className="link">跳转About页面</NavLink><Switch><Route path="/home" component={Home}/><Route path="/about" component={About}/><Route path="/home" component={Home}/><Route path="/home" component={Home}/>{/* 此处省略一万个Route组件 */}<Route path="/home" component={Home}/></Switch></Router></div>);}export default App;
效果如下:

要点总结:将多个
Route组件同时放在一个Switch组件中,即可避免多次无意义的路由匹配,以此提升性能重定向
当页面跳转时,若跳转链接没有匹配上任何一个
Route组件,那么就会显示404页面,所以需要一个重定向组件Redirect,代码如下:import {BrowserRouter as Router,Route,NavLink,Switch,Redirect,} from 'react-router-dom'import Home from './home'import About from './about'function App() {return (<div className="App"><Router><NavLink to="/home" className="link">跳转Home页面</NavLink><NavLink to="/about" className="link">跳转About页面</NavLink><NavLink to="/shop" className="link">跳转Shop页面</NavLink> {/* 点击,跳转到/shop,但该路径没有设置 */}<Switch><Route path="/home" component={Home}/><Route path="/about" component={About}/><Redirect to="/home" /> {/* 当以上Route组件都匹配失败时,重定向到/home */}</Switch></Router></div>);}export default App;
路由传参
所有路由传递的参数,都会在跳转路由组件的
props中获取到,每种传参方式接收的方式略有不同
路由传参的方式一共有三种,依次来看一下第一种
第一种是在
Link组件的跳转路径上携带参数,并在Route组件的匹配路径上通过:参数名的方式接收参数,代码如下:import {BrowserRouter as Router,Route,NavLink,Switch,} from 'react-router-dom'import Home from './home'import About from './about'function App() {return (<div className="App"><Router>{/* 在 /home 的路径上携带了 张三、18 共两个参数 */}<NavLink to="/home/张三/18" className="link">跳转Home页面</NavLink><NavLink to="/about" className="link">跳转About页面</NavLink><Switch>{/* 在 /home 匹配路径上相同的位置接收了 name、age 两个参数 */}<Route path="/home/:name/:age" component={Home}/><Route path="/about" component={About}/></Switch></Router></div>);}export default App;
尝试跳转,并打印一下路由组件的
props
可以看到,第一种方式的参数是通过props.match.params来获取的第二种
第二种方式就是通过在
Link组件的跳转链接后面跟上以?开头,类似?a=1&b=3这样的参数进行传递,代码如下:import {BrowserRouter as Router,Route,NavLink,Switch,} from 'react-router-dom'import Home from './home'import About from './about'function App() {return (<div className="App"><Router>{/* 在跳转路径后面以?开头传递两个参数,分别为name=张三、age=18 */}<NavLink to="/home?name=张三&age=18" className="link">跳转Home页面</NavLink><NavLink to="/about" className="link">跳转About页面</NavLink><Switch>{/* 此处无需做接收操作 */}<Route path="/home" component={Home}/><Route path="/about" component={About}/></Switch></Router></div>);}export default App;
尝试跳转,并打印一下路由组件的
props
可以看到,第二种方式的参数是通过props.location.search来获取的,不过这里的参数需要自己简单做进一步转化。第三种
第三种方式就是以对象的形式编写
Link组件的to跳转属性,并通过state属性来传递参数,代码如下:import {BrowserRouter as Router,Route,NavLink,Switch,} from 'react-router-dom'import Home from './home'import About from './about'function App() {return (<div className="App"><Router>{/* 以对象的形式描述to属性,路径属性名为pathname,参数属性名为state */}<NavLink to={{pathname: "/home", state: {name: '张三', age: 18}}} className="link">跳转Home页面</NavLink><NavLink to="/about" className="link">跳转About页面</NavLink><Switch>{/* 此处无需特地接收属性 */}<Route path="/home" component={Home}/><Route path="/about" component={About}/></Switch></Router></div>);}export default App;
尝试跳转,并打印一下路由组件的
props
可以看到,第三种方式的参数是通过props.location.state来获取的函数式路由
以上主要都是通过
react-router-dom中的Link组件来往某个路由组件跳转
但有时,需要更灵活的方式进行跳转路由,例如通过调用一个函数,随时随地进行路由跳转,这就叫函数式路由
函数式路由用到的方法有以下5个(下方截图来自路由组件的props)
5个方法分别是push、replace、goForward、goBack、go,接下来按顺序介绍一下这几个方法push
push方法就是使页面跳转到对应路径,并在浏览器中留下记录(即可以通过浏览器的回退按钮,返回上一个页面)
举个例子:在路由组件Home中设置一个按钮button,点击后调用push方法,跳转到/about页面import React from 'react'function Home (props) {let pushLink = () => {props.history.push('/about')}return (<div className="a">我是Home页面<button onClick={pushLink}>跳转到about页面</button></div>)}export default Home
跳转效果如下:

可以看到,通过push方法跳转以后,可以通过浏览器的回退按钮,返回上一个页面replace
replace方法与push方法类似,不一样的地方就是,跳转后不会在浏览器中保存上一个页面的记录(即无法通过浏览器的回退按钮,返回上一个页面)
改动一下代码import React from 'react'function Home (props) {let replaceLink = () => {props.history.replace('/about')}return (<div className="a">我是Home页面<button onClick={replaceLink}>跳转到about页面</button></div>)}export default Home
跳转效果如下:

可以看到,刚开始的路径是 ‘/‘ ,然后跳转到 ‘/home’ ,再点击按钮,通过replace方法跳转到/about页面。最后通过浏览器的回退按钮返回到了/页面,说明中间的/home没有被存在浏览器的记录里goForward
调用
goForward方法,就相当于点击了浏览器的返回下一个页面按钮,如下图所示:
goBack
调用
goBack方法,就相当于点击了浏览器的返回上一个页面的按钮,如下图所示:
go
go方法顾名思义,是用于跳转到指定路径的。
该方法接受一个参数(参数类型为Number),情况如下:当参数为正数
n时,表示跳转到下n个页面。例如go(1)相当于调用了一次goForward方法- 当参数为负数
n时,表示跳转到上n个页面。例如go(-3)相当于调用了三次goBack方法 -
普通组件使用路由
这里区分两个概念,分别为 普通组件 和 路由组件
通过Route组件渲染的组件为路由组件 ,其余的基本上都为 普通组件
例如,下方代码中:Home组件为路由组件 ;App组件为普通组件import {BrowserRouter as Router,Route,NavLink,Switch,} from 'react-router-dom'import Home from './home'export default function App() {return (<div className="App"><Router><NavLink to='/home' className="link">跳转Home页面</NavLink><Switch><Route path="/home" component={Home}/></Switch></Router></div>);}
然后,路由组件跟普通组件最大的区别就是,组件的
props属性中是否有下图所示的内容:(前者有,后者无)
此时,react-router-dom提供了一个withRouter方法,可以使普通组件也能像路由组件一样有那些方法或数据可以使用
使用方法如下:import {BrowserRouter as Router,Route,NavLink,Switch,withRouter, // 1. 引入 witRouter} from 'react-router-dom'import About from './about'function App(props) {console.log(props); // 3. 尝试打印普通组件App的props,发现此时props中已有内容了,即普通组件也能拥有跟路由组件一样类似的功能return (<div className="App"><Router><NavLink to="/about" className="link">跳转About页面</NavLink><Switch><Route path="/about" component={About}/></Switch></Router></div>);}export default withRouter(App); // 2. 通过withRouter方法对普通组件做一层包装处理
补充
replace
在函数式路由里跳转类型主要有两种,分别是
push和replace,那么在非函数式路由中,同样也可以自定义跳转类型,具体的实现代码如下:import {BrowserRouter as Router,Route,Link} from 'react-router-dom'import Home from './home'import About from './about'function App() {return (<div className="App"><Router><Link to="/home" className="link">跳转Home页面</Link><Link to="/about" className="link">跳转About页面</Link><Route path="/home" component={Home} replace={true}/> {/* replace为true,跳转类型为replace */}<Route path="/about" component={About} replace={false}/> {/* replace为false,跳转类型为push */}</Router></div>);}export default App;
Route组件上有个replace属性可以设定跳转类型,当值为true时,跳转类型为replace; 为false时,跳转类型为pushexcat
路由的匹配默认是模糊匹配的,举个例子:
import {BrowserRouter as Router,Route,Link,} from 'react-router-dom'import Home from './home'import About from './about'function App() {return (<div className="App"><Router><Link to="/home/abc">跳转Home页面</Link> {/* 跳转到/home/abc,但实际home下没有abc这个路由组件 */}<Link to="/about/abc">跳转About页面</Link> {/* 跳转到/about/abc,但实际home下也没有abc这个路由组件 */}<Route path="/home" component={Home} /> {/* 路由匹配规则为/home,没有设置exact属性,当前为模糊匹配 */}<Route path="/about" component={About} exact/> {/* 路由匹配规则为/about,设置了exact属性,当前为精准匹配 */}</Router></div>);}export default App;
效果如下:

图中看出,因为跳转/home/abc时,第一个Route组件是模糊匹配的,所以先匹配到了/home,因此Home组件渲染了 ; 而跳转/about/abc时,第二个Route组件是精准匹配的,即/about/abc不等于/about,所以About组件也没有渲染
总结: 如果想要精准匹配的话,只需要将
Route组件的exact属性设置为true即可- 精准匹配要谨慎使用,因为可能会影响嵌套路由的使用
