1.安装
// npm 安装
npm install --save react-router-dom
// yarn 安装
yarn add react-router-dom --save
2.BrowserRouter & HashRHashRouter
<HashRouter>在url上会出现#,<BrowserRouter>则不会
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom'
import App from './App'
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
)
3.<Route>
根据匹配路径渲染组件,三种渲染方法:component、render、children。使用render时,需要将props传递至子组件,否则子组件获取不到history对象
// component,渲染<Home>组件
<Route path='/home' component={Home}/>
// render传入函数,返回值为组件,通过props将history对象传入<About>组件
<Route path='/about' render={(props) => (
<About {...props} />
)}/>
// 可在render函数中做一些操作
<Route path='/about' render={(props) => {
document.title = 'xxx'
return <About {...props} />
}}/>
4.<Switch>
仅渲染第一个路径匹配成功的<Route>组件。在没有使用<Switch>组件包裹的<Route>中,当path为'/home'或者'/about',<Always>组件始终会渲染
<Route path='/home' component={Home}/>
<Route path='/about' render={(props) => (
<About {...props} />
)}/>
<Route component={Always}/>
使用<Switch>组件,始终只渲染一个组件,没有路径匹配成功将渲染<Always>组件
<Switch>
<Route exact path='/' component={Home}/> // 精准匹配初始路径'/'
<Route path='/home' component={Home}/>
<Route path='/about' render={(props) => {
return <About {...props} />
}}/>
<Route component={Always}/>
</Switch>
5.<Link> & <NavLink>
两个组件最终都渲染成<a>标签,通过 to 指定路径名,to 可传入字符串或对象;replace属性值为true,将替换当前页面
// string
<Link to="/home" replace={true}>
// object,search属性值将在url上显示,state对象可在组件的history对象中获取
<Link to={{pathname: '/home', search: '?id=1', state: { type: true } }}>
<NavLink>多两个属性,可添加被激活时的className、style属性
// 当前激活的<NavLink>的class会增加‘tab-active’
<NavLink to="/home" activeClassName="tab-acitve">
<NavLink to="/about" activeClassName="tab-acitve">
// 使用style属性
<NavLink to="/home" activeStyle={{color: '#000'}}>
<NavLink to="/about" activeStyle={{color: '#000'}}>
6.路由匹配
<NavLink to="/about?id=1">about</NavLink>
// Route
<Route path='/about' component={About}/>
动态路由匹配
<NavLink to="/about/1">about</NavLink>
// Route匹配url:/about/1、/about/2
<Route path='/about/:id' component={About}/>
7.获取参数值
<Route>将history对象下传至组件内部,组件通过props接收,通过history对象获取参数信息。使用render属性还可以额外传递其他数据
class Home extends Component {
render() {
let user = { name: 'Tom' }
return (
<Switch>
<Route path="/home" component={Home} />
<Route path='/about' render={(props) => (
<About {...props} user={user} />
)} />
</Switch>
)
}
}
class组件通过this.props接收,根据是否为动态路由,根据 this.props.match(动态路由) / this.props.location 获取 url 信息以及参数
// class
class Home extends Component {
render() {
console.log(this.props)
return (
<div>Abou</div>
)
}
}
// 函数
const Contact = (props) => {
console.log(props)
return (
<div>Contact</div>
)
}
// 函数解构写法
const Contact = ({location, match}) => {
console.log(location, match)
return (
<div>Contact</div>
)
}
8.编程式导航
组件内部通过 this.props.history 进行编程式导航
push(path, [state])
replace(path, [state])
go(n) - (function 类型) 将 history 堆栈中的指针调整 n
goBack() - (function 类型) 等同于 go(-1)
goForward() - (function 类型) 等同于 go(1)
this.props.history.push('/home?id=118', {type: 1})
'/home?id=118' 由 history.location.search获取
{type: 1} 由 history.location.state获取
9.withRouter
以上例子中,class组件与函数组件都能通过 props 获取 history 对象,从而得到 url 相关信息以及参数。原因在于,这些组件都是通过 <Route> 组件渲染,<Route> 组件将 history 对象下传至需要渲染的组件
在项目中,并不是所有的组件都通过<Route> 组件渲染,只有“框架性”的页面才由 <Route> 渲染,例如主页、个人中心页(需要改变 url 进行跳转的页面),这些页面中包含的小组件不通过 <Route> 渲染,所以没有 history 对象
首页中的商品列表组件
import React, { Component } from 'react'
class GoodList extends Component {
render() {
console.log('GoodList: ', this.props)
return (
<div onClick={() => { this.props.history.push('/good') }}>查看详情</div>
)
}
}
export default GoodList
由于 <GoodList> 组件不是由 <Route> 渲染,所以 props 中没有 history 对象,点击时会出错
解决方法:使用 withRouter,将获得最近一层由 <Route> 渲染的组件的 history 对象,<GoodList> 将获得 <Home> 组件(由 <Route> 渲染)的 history 对象
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
class GoodList extends Component {
render() {
console.log('GoodList: ', this.props)
return (
<div onClick={() => { this.props.history.push('/good') }}>查看详情</div>
)
}
}
export default withRouter(GoodList)