共计 7575 个字符,预计需要花费 19 分钟才能阅读完成。
手挽手带你学 React 入门三档, 带你学会使用 Reacr-router4.x, 开始创建属于你的 React 项目
什么是 React-router
React Router 是一个基于 React 之上的强大路由库,它可以让你向应用中快速地添加视图和数据流,同时保持页面与 URL 间的同步。通俗一点就是,它帮助我们的程序在不同的 url 展示不同的内容。
为什么要用 React-router
我们开发的时候,不可能所有的东西都展示在一张页面上,在业务场景的要求下,我们要根据不同的 URL 或者不同的哈希来展示不同的组件,这个我们可以称它为路由。在我们不使用 React-router 的时候,我们如何去做路由呢?
我在这里给大家举个例子,不使用 React-router,来实现一个简单路由。
// App.js
import React,{Component} from ‘react’
export default class App extends Component {
constructor(){
super()
// 我们在 App.js 内部来渲染不同的组件 我们这里采用哈希路由的方式,鉴于 React 的渲染机制,我们需要把值绑定进入 state 内部。
this.state={
route:window.location.hash.substr(1)
}
}
componentDidMount() {
// 这里我们通过监听的方式来监听哈希的变化,并且来更新 state 促进视图更新
window.addEventListener(‘hashchange’, () => {
console.log(window.location.hash.substr(1))
this.setState({
route: window.location.hash.substr(1)
})
})
}
render() {
// 在这里我们定义一个 RouterView 所有的变化后的组件都会丢到这个 RouterView 中
let RouterView = App
switch (this.state.route) {
case ‘/children1’:
RouterView = Children
break;
case ‘/children2’:
RouterView = ChildrenTwo
break;
default:
RouterView = Home
break;
}
return (
<div>
<h1>App</h1>
<ul>
<li><a href=”#/children1″>children1</a></li>
{/* 点击更改哈希值 这里触发我们的监听 然后修改 state 来触发组件的重新传染 */}
<li><a href=”#/children2″>children2</a></li>
</ul>
<RouterView/>
</div>
)
}
}
// 为了展示效果定义子组件一
class Children extends Component{
constructor(){
super()
this.state={
}
}
render(){
return(
<div>
<h1> 我是子组件 1 </h1>
</div>
)
}
}
// 为了展示效果定义子组件二
class ChildrenTwo extends Component{
constructor(){
super()
this.state={
}
}
render(){
return(
<div>
<h1> 我是子组件 2 </h1>
</div>
)
}
}
// 为了展示效果定义 Home 组件
class Home extends Component{
constructor(){
super()
}
render(){
return(
<h1> 我是 Home</h1>
)
}
}
这样我们通过监听哈希变化的方式实现了我们的第一个简单路由,是不是对于路由的原理有了那么一丢丢的认识呢?接下来我们想象一个场景,这么一个路由出现了 /children1/user/about/1,看到这里是不是觉得,用 switch case 已经蒙 B 了?我们接下来就要使用到 React-router 了,这个东西可不需要我们自己去写一大串的 switch case 了,并且性能啊,整洁度啊等等等方面都比我们自己写的好多了!
React-router 初体验
首先我们在 React 项目文件目录下执行
npm install react-router-dom –save
npm install react-router –save
要想体验一个新的东西,当然是要拿自己开刀 我们改进上面我们写过的组件
// App.js
import React,{Component} from ‘react’
// 首先我们需要导入一些组件 …
import {HashRouter as Router, Route, Link} from “react-router-dom”;
// 这里有 BrowserRouter 和 HashRouter 两种模式 我比较推荐 HashRouter 来学习 BrowserRouter 需要后端配合 单独前端设置 刷新会出现 404
// 然后我们把 App 组件整理干净,大概成这个样子
export default class App extends Component {
constructor(){
super()
this.state={
}
}
render() {
return (
<Router>
<div>
<h1>App</h1>
<ul>
<li> <Link to=”/”>Home</Link></li>
<li><Link to=”/children1/”>children1</Link></li>
<li><Link to=”/children2/”>children2</Link></li>
</ul>
<Route exact path=”/” component={Home} />
<Route path=”/children1″ component={Children} />
<Route path=”/children2″ component={ChildrenTwo} />
</div>
</Router>
)
}
}
// 为了展示效果定义子组件一
class Children extends Component{
constructor(){
super()
this.state={
}
}
render(){
return(
<div>
<h1> 我是子组件 1 </h1>
</div>
)
}
}
// 为了展示效果定义子组件二
class ChildrenTwo extends Component{
constructor(){
super()
this.state={
}
}
render(){
return(
<div>
<h1> 我是子组件 2 </h1>
</div>
)
}
}
// 为了展示效果定义 Home 组件
class Home extends Component{
constructor(){
super()
}
render(){
return(
<h1> 我是 Home</h1>
)
}
}
这里我们就完成了 React-router4.X 的初步体验, 怎么样~ 我给大家的第一次的感觉还可以吧~
基本组件
Routers 在 React-router4.0 中,Routers 有两个表现方式 <BrowserRouter> 和 <HashRouter> 这两个标签都将会给你创建一个专门的 history 对象,BrowserRouter 的表现模式需要搭配一个可以响应请求的服务器。HashRouter 是静态文件服务器,我们本地开发的时候,建议使用 HashRouter。这里需要注意一下,BrowserRouter 和 HashRouter 标签下面,只允许存在一个标签 具体写法如下
<BrowserRouter>
<div>
{/* 其余内容写在这里面 */}
</div>
</BrowserRouter>
<HashRouter>
<div>
{/* 其余内容写在这里面 */}
</div>
</HashRouter>
Route 注意,最外层的是 Router 这里是 Route 这是我们的路由匹配组件,它有两个 Route 和 Switch Route 组件拥有多个属性,这在我们后期的路由传参中将会用到。这里我们需要简单了解几个属性 path component exact strict path 是我们匹配的地址,当地址匹配的时候 我们才会去渲染 component 内的组件内容 path 后面如果书写模式带了 /: 这样的内容,那么这里将会成为占位符 我们可以利用占位符来取到对应路径的参数 使用 this.props.match.params+ 占位符的名字 即可拿到 exact 属性来规定我们是否严格匹配 strict 则是严格匹配模式 我们规定的路径使用 /one/ 来书写 如果没有完全匹配 /one/ 则不会展示
<Route exact path=”/one” component={App} />
// 这里我们加了 exact 那么 路径完全等于 /one 的时候才会渲染 App /one/ one /one/two 后面这三种情况均不会渲染 App
// 相反 如果我们没有加 exact 的时候 /one /one/two App 都会被渲染
<Route strict path=”/one/” component={App} />
// 我们加了 strict 以后 /one 将不会渲染 App 而如果没有 strict 这种情况下 /one 是可以渲染 App 的
同时 React-router 给我们提供了一个 Switch 标签 在这个标签内 我们只会渲染一个 Route 并且使第一个符合条件的 Route 这是什么意思呢?我们来看代码
<Route path=”/about” component={About} />
<Route path=”/:User” component={User} />
<Route path=”/” component={Home} />
<Route component={NoMatch} />
在这样的路由下 我们匹配 /about 会发现 所有的路由都可以匹配到并且渲染了出来,这肯定不是我们想要的结果 于是我们给它嵌套一个 Switch
<Switch>
<Route path=”/about” component={About} />
<Route path=”/:User” component={User} />
<Route path=”/” component={Home} />
<Route component={NoMatch} />
</Switch>
这时候我们就只会匹配到第一个 /about, 仅仅渲染 About, 大家根据实际需求去决定是否嵌套 Switch 使用
Link 和 NavLink
Link 主要 api 是 to,to 可以接受 string 或者一个 object,来控制 url。我们代码里看看书写方法
<Link to=’/one/’ />
// 这就是路由到 one 搭配 Router 使用 当然我们可以使用一个对象
<Link to={{
pathname:’/one’,
search:’?name=qm’,
hash:’#two’,
state:{
myName:’qimiao’
}
}} />
// 这样我们点击 link 不仅可以到 one 还可以传递一些参数
NavLink 它可以为当前选中的路由设置类名、样式以及回调函数等。使用如下
<NavLink exact activeClassName=’navLink’ to=’/one/’ />
// 这就是路由到 one 搭配 Router 使用 当然我们可以使用一个对象
<NavLink exact activeClassName=’navLink’ to={{
pathname:’/one’,
search:’?name=qm’,
hash:’#two’,
state:{
myName:’qimiao’
}
}} />
// 这里的 exact 同样是严格比配模式 同 Route
// 这样我们可以为当前选中的路由设置样式了
子路由的书写
在 react-router4 之前的版本,子路由通过路由嵌套就可以实现了,但是这一个方法到了 React-router4 中就行不通了
先来一个之前的写法,当然也是错误示例
export default class App extends Component {
constructor(){
super()
this.state={
}
}
render() {
return (
<Router>
<div>
<h1>App</h1>
<ul>
<li> <Link to=”/home”>Home</Link></li>
<li><Link to=”/children1/”>children1</Link></li>
<li><Link to=”/children2/”>children2</Link></li>
</ul>
<Route path=”/home” component={Home} >
<Route path=”children1″ component={Children} />
<Route path=”children2″ component={ChildrenTwo} />
{/* 在 4.0 以后的版本这样都会报错 那么我们应该怎么写呢 */}
</Route>
</div>
</Router>
)
}
}
在 react-router4.x 版本中 我们子路由必须要在子组件内部了
export default class App extends Component {
constructor(){
super()
this.state={
}
}
render() {
return (
<Router>
<div>
<h1>App</h1>
<ul>
<li> <Link to=”/home”>Home</Link></li>
{/* 同样 这两个 link 让他们转移到 Home 中 我们的 home 组件就变成了下面的样子 */}
</ul>
<Route path=”/home” component={Home} >
{/*<Route path=”children1″ component={Children} />*/}
{/*<Route path=”children2″ component={ChildrenTwo} />*/}
{/* 先把这里注释掉 然后我们来到 Home 组件内 */}
</Route>
</div>
</Router>
)
}
}
// home 内部用 {this.props.match.url+ 子路由路径} 来获取当前的路径并且加上我们要路由到的位置来进行路由匹配和路径跳转匹配 这样书写 Children 和 ChildrenTwo 就是 home 的子路由了
class Home extends Component{
constructor(){
super()
}
render(){
return(
<div>
<h1> 我是 Home</h1>
<li><Link to={`${this.props.match.url}/children1`}>children1</Link></li>
<li><Link to={`${this.props.match.url}/children2`}>children2</Link></li>
<Route path={`${this.props.match.url}/children1`} component={Children} />
<Route path={`${this.props.match.url}/children2`} component={ChildrenTwo} />
</div>
)
}
}
路由跳转
声明式跳转上面已经说过了 Link 和 NavLink 两个标签就可以满足了 我们主要说一下 js 跳转在 4.0 刚刚发布的时候 this.props.history.push(‘ 路径 ’)这个方法已经行不通了,不过值得庆幸的是,我现在所使用的 4.3.1 版本又可以使用这个方法来进行 js 路由跳转了。
我们用 home 组件来举个例子
class Home extends Component{
constructor(){
super()
}
toPath=(home)=>{
console.log(123)
this.props.history.push({// 我们把要传参的东西都放在 push 对象内了
pathname:home, // 我们要到达哪个路由
search:”?a=1″, // 明文传参的模式
query:{‘type’:’type’}, //query 对象传参
state:{//state 对象传参
b:456
}
})
// this.props.history.push(‘/123’)
}
render(){
return(
<div>
<h1 onClick={()=>{this.toPath(`${this.props.match.url}/children1/123`)}}> 我是 Home</h1>
<li><Link to={`${this.props.match.url}/children1`}>children1</Link></li>
<li><Link to={`${this.props.match.url}/children2`}>children2</Link></li>
<Route path={`${this.props.match.url}/children1/:id`} component={Children} />
<Route path={`${this.props.match.url}/children2`} component={ChildrenTwo} />
</div>
)
}
}
/* 相应的 我们在 Children 组件里面有对应的方法来获取参数。*/
class Children extends Component{
constructor(){
super()
this.state={
}
}
render(){
console.log(this.props.match.params.id) // 这种是通过路径上面的:id 传过来的参数
console.log(this.props.location.query) // 这是通过 push 的参数对象中的 query 传过来的 和 vue 的 query 有区别 它不在地址栏 刷新丢失
console.log(this.props.location.state) // 这是通过 push 的参数对象中的 state 传过来的 它不在地址栏 刷新丢失
console.log(this.props.location.search) // 暴露在地址栏,需要自行处理获取数据
return(
<div>
<h1> 我是子组件 1 </h1>
</div>
)
}
}
总结
这一期我们主要还是讲了 react-router4.x 的基础使用和传参方法,react-router4.x 坑比较多,不过使用熟练了会让你感觉很爽,大家不要吝啬自己的时间多多学习,博客开通了注册投稿功能,如果大家有好的学习文章,经典总结,可以投稿,可以扫码加我微信申请专栏~ 感谢大家的阅读和观看。
视频制作中