手挽手帶你學React:三檔 React-router4.x的使用

手挽手帶你學React入門三檔,帶你學會使用Reacr-router4.x,開始建立屬於你的React項目javascript

什麼是React-router

React Router 是一個基於 React 之上的強大路由庫,它可讓你嚮應用中快速地添加視圖和數據流,同時保持頁面與 URL 間的同步。通俗一點就是,它幫助咱們的程序在不一樣的url展現不一樣的內容。前端

爲何要用React-router

咱們開發的時候,不可能全部的東西都展現在一張頁面上,在業務場景的要求下,咱們要根據不一樣的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-router 初體驗

首先咱們在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坑比較多,不過使用熟練了會讓你感受很爽,你們不要吝嗇本身的時間多多學習,博客開通了註冊投稿功能,若是你們有好的學習文章,經典總結,能夠投稿,能夠掃碼加我微信申請專欄~感謝你們的閱讀和觀看。

視頻製做中

相關文章
相關標籤/搜索