最近用了几次react-router感觉对其使用还不够熟练,所以看着官方文档复习了一下,顺便做个笔记。
因为webpack懒得搭环境了 所以直接上parcel 0 配置 很好用 但是正式开发我还是喜欢webpack 因为足够灵活
先上demo的 github链接
这是官方文档链接
匹配原理
Route 组件匹配采用从上到下依次匹配,直到最后一个路由或者无可匹配的路由为止。若想只匹配一个路由,请使用Switch组件
基本使用
选择Router:
react-router 提供了五种router供选择,但前端常用到的就三种,具体区别 见文档, 这次选择 BrowserRouter
Router 需要传递history
BrowserRouter (官方推荐) 使用时需要服务器配合配置,若使用webpack开发需打开historyApiFallback选项
HashRouter url中有一个#号
开始配置
初始配置
现在有三个页面 home , book 和 book的子页面kongfu,如下
<li><Link to='/'>home</Link></li>
<li><Link to='/movie'>movie</Link></li>
<li><Link to='/movie/kongfu'>kongfu</Link></li>
<Route path='/' component={Home} />
<Route path='/movie' component={Movie} />
<Route path='/movie/kongfu' component={KongFu} />
每一个被匹配到的路由均渲染了对应的组件,效果图如下:
![](https://img.haomeiwen.com/i5436992/d1d2674310d6db6b.gif)
若我们想只匹配一个组件怎么办?往下看。
使用Switch组件
修改上面的路由部分代码,添加Switch组件
<Switch>
<Route path='/' component={Home} />
<Route path='/movie' component={Movie} />
<Route path='/movie/kongfu' component={KongFu} />
</Switch>
无论跳转到任何一个路由都只会匹配第一个路由home。效果图如下:
![](https://img.haomeiwen.com/i5436992/637fc60c43beccfe.gif)
但是我们并不想要这样的结果,有两个办法可以解决
- 把最精确的路由放在最前面
- Route组件添加exact属性
如下
// 第一种方法
<Switch>
<Route path='/movie/kongfu' component={KongFu} />
<Route path='/movie' component={Movie} />
<Route path='/' component={Home} />
</Switch>
// 第二种方法
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/movie' component={Movie} />
<Route exact path='/movie/kongfu' component={KongFu} />
</Switch>
效果图如下:
![](https://img.haomeiwen.com/i5436992/3bb66c418697cec6.gif)
布局
单个布局
我们日常使用过程中经常会有导航栏或者侧边栏的需求,如下。
header作为导航栏部分, main作为匹配路由的部分
<header style={{backgroundColor:'#b8cca6'}}>
<h1>This is header</h1>
</header>
<main style={{backgroundColor:'#26899e'}}>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/movie' component={Movie} />
<Route exact path='/book' component={Book} />
</Switch>
</main>
为了效果,明显对header以及main部分加了背景色,如下图:
![](https://img.haomeiwen.com/i5436992/71196ca1a8c13c8f.gif)
如果我们有多个布局怎么办? 比如常见的还有登录布局,往下看。
多个布局
为实现多个布局我们将多个布局提取成多个组件
/***** BasicLayout.jsx *****/
<div>
<h1>BasicLayout!!</h1>
<Route exact path='/' component={Home} />
<Route exact path='/movie' component={Movie} />
<Route exact path='/book' component={Book} />
</div>
/***** LoginLayout.jsx *****/
<div>
<h1>LoginLayout!!</h1>
<form action="">
username: <input type="text" placeholder='please input username'/>
<br />
password: <input type="password" placeholder='please input password'/>
</form>
</div>
/***** App.jsx *****/
// 注意 有子路由的Route不要加exact不然会匹配不到子路由,
<Switch>
<Route path='/login' component={LoginLayout} />
<Route path='/' component={BasicLayout} />
</Switch>
如下图:
![](https://img.haomeiwen.com/i5436992/a4ea0e92b1f079f4.gif)
登录验证
既然有登录布局 自然就需要有登录验证
官方推荐的做法是自己实现一个AuthRoute,如下
const AuthRoute = (props) => {
const { component:Component, ...rest } = props;
// parcel 默认不支持rest参数, 需添加babel-plugin-transform-object-rest-spread 并添加到.babelrc文件中
// const rest = {};
// for (const _key in props) {
// if(_key !== 'component') {
// rest[_key] = props[_key]
// }
// }
return (<Route
{...rest}
render={(props) => (
islogin()?
(<Component {...props} />)
:
(<Redirect to='/login' />)
)}
/>)
}
此处有两个小坑,
- parcel默认不支持rest参数,具体看上面代码注释。
- Route组件的 component 和 render 都会在路径匹配时渲染组件,但component优先级较高,若两个属性同时出现render会被忽略。
下面看下效果:
首先是未登录状态 任何路由都无法进入 只能停留在login页
![](https://img.haomeiwen.com/i5436992/8c42a89c1fcb1963.gif)
下面是登陆后的效果,任何路由都可以访问,登出后之能访问login页
![](https://img.haomeiwen.com/i5436992/d918d851613dfd56.gif)
编程式导航
既然有了登录验证 那我们总不能让用户自己点其他路由跳转到首页吧! 下面就来使用withRouter 在登陆成功后让代码手动跳转到首页
const { history } = this.props
history.push('/');
被Route包裹的组件都会在props拥有history,match,location对象,使用hisory对象的push方法即可进行手动跳转。
效果如下图:
![](https://img.haomeiwen.com/i5436992/9257d7f864a7a742.gif)
withRouter
若在Route组件之外想要访问 history,match,location对象并做一些操作呢?
这时候withRouter就排上用场了,
每次路由发生变化时Router包裹的组件会被重新渲染,
withRouter包裹的组件就可访问到路由信息对象,就可以响应路由变化
我们改造一下导航部分 将其封装成一个Nav组件, 在export时用withRouter包裹。
import { withRouter, Link } from 'react-router-dom';
class Nav extends Component {
render() {
const activeStyle = {
backgroundColor: '#00a74a'
}
const path = this.props.location.pathname;
console.log('test', this.props)
return (
<ul>
<li><Link to='/login' style={path === '/login'?activeStyle:{}} >login</Link ></li>
<li><Link to='/' style={path === '/'?activeStyle:{}} >home</Link ></li>
<li><Link to='/movie' style={path === '/movie'?activeStyle:{}}>movie</Link ></li>
<li><Link to='/book' style={path === '/book'?activeStyle:{}}>book</Link ></li>
</ul>
)
}
}
export default withRouter(Nav);
效果如下图:
![](https://img.haomeiwen.com/i5436992/cc452a094ea6999a.gif)
以上就是一些react-router v4的一些基本使用。若有错误欢迎指出!
Tips: 注意看文中的Route 和Router 就差一个字母 不要看花了眼哦
网友评论