手挽手带你学React入门三档,带你学会使用Reacr-router4.x,开始建立属于你的React项目javascript
React Router 是一个基于 React 之上的强大路由库,它可让你向应用中快速地添加视图和数据流,同时保持页面与 URL 间的同步。通俗一点就是,它帮助咱们的程序在不一样的url展现不一样的内容。前端
咱们开发的时候,不可能全部的东西都展现在一张页面上,在业务场景的要求下,咱们要根据不一样的URL或者不一样的哈希来展现不一样的组件,这个咱们能够称它为路由。在咱们不使用React-router的时候,咱们如何去作路由呢?vue
我在这里给你们举个例子,不使用React-router,来实现一个简单路由。java
// 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
首先咱们在React项目文件目录下执行npm
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的初步体验,怎么样~我给你们的第一次的感受还能够吧~api
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坑比较多,不过使用熟练了会让你感受很爽,你们不要吝啬本身的时间多多学习,博客开通了注册投稿功能,若是你们有好的学习文章,经典总结,能够投稿,能够扫码加我微信申请专栏~感谢你们的阅读和观看。