React Router


路由可以向應用中快速的添加視圖和數據流,同時保持頁面與URL同步

import {Router ,Route, Link} from 'react-router'

class App extends React.Component {
        render(){
             return (
                <div>
                    <ul >
                        <li><Link to='/about'>About</Link></li>
                        <li><Link to='/inbox'>Inbox</Link></li>
                    </ul>
                    {this.props.children}
                </div>
                )}})
//獲取URL參數
class Message extends React.Component{
    componentDidMount(){
      const id = this.props.params.id //來自於路徑 ‘/inbox/messages/:id'
      
      fetchMessage(id,function(err,message){
        this.setState({message:message})
      })
  }
  render(){
    return(
      <div>
          <h3>message{this.props.params.id}</h3>
      </div>

}

React.render((
<Router> <Route path='/' component={App}> <Route path='about' component={About} /> <Route path='inbox' component={Inbox} onEnter={requireAuth}>
                  <Route path='messages/:id component={Message} />
              </Route>
</Route> <Router> ).document.body);

以上獲取URL參數方法:

1 id = this.props.params.id        來自父組件路徑path=‘/index/message.:id'

2 baz= this.props.location.query.bar   訪問路徑為  /foo?bar=baz 時,獲取baz的值

3 newhash = window.location.hash 簡單的用於跳轉,不用存儲location state

添加首頁:IndexRouter 設置默認頁面,當App的render中this.props.children還是undefined時顯示

<IndexRoute component={Dashboard}/>

IndexLink

如果使用<Link to='/'>Home</Link>,他會一直處於激活狀態,因為所有的URL開頭都是‘/'。而我們希望僅僅在home被渲染之后才激活並鏈接它。  可以使用<IndexLink to='/'>home</IndexLink>.

簡潔的URL:使用絕對路徑,無需在URL中添加更多的層級,從而可以使用更簡潔

<Route path='/messages/:id' component={Message}/>  但其可能在動態路由中無法使用

重定向Redirect 

<Redirect from='message/:id' to='/message/:id'/>

當有人點擊/inbox/message/5時,會跳到/message/5,以防/inbox/message/5不存在

onEnter和onLeave進入和離開的hook,在頁面跳轉確認時觸發。例如 權限驗證,或數據持久保存

onLeave hook 在所有將離開的路由中觸發,從最下層的字路由開始到最外層的父路由結束。

onEnter hook從最外層的父路由開始到最下層的字路由結束

例如:從/messages/5跳到/about,hook的執行順序:/messages/:id的onLeave->/inbox的onLeave->/about的onEnter

requireAuth(nextState,replace,callback){if(isLogined){replace('./home');}else{replace('./login');}callback();}

路徑語法

:paramName 匹配位於/ ? # 之后的URL;稱作參數

() 在其內部的內容是可選的

* 匹配任意字符

History

一個history知道如何去監聽瀏覽器地址欄的變化,並解析這個url轉化為location對象,然后router使用它匹配到路由,渲染對應的組件。

1  browserHistory   

使用瀏覽器中的 historyAPI 用於處理URL,創建 example.com/some/path這樣的真實URL 

2  hashHistory

我使用URL中的hash#部分去創建形如 example.com/#/some/path的路由.window.location.hash = newhash

3 creactMemoryHistory

Memory history 不會在地址欄被操作或讀取,非常適合測試和其他渲染環境。但必須創建

const history = createMemoryHistory(location)

 

高級進階

動態路由:

根據‘按需加載’的原則,路由非常適合做代碼拆分:他的責任就是配置好每個view。

react router 的 路徑匹配 及 組件加載 都是異步完成的,不僅允許你延遲加載組件,也可以延遲加載 路由的配置。在首次加載包中只需要有一個路徑定義,路由會自動解析剩下的路徑。

route定義的函數 getChildRoutes、getIndexRoute、getComponents  都為異步加載‘逐漸匹配’

const CourseRoute = {
path:'cource/:id',

getChildRoutes(location,callback){
    require.ensure([],function(require){
        callback(null,[
            require('./routes/Announcements'),
            require('./routes/Assignments'),
            require('./routes/Grades'),
          ])})},

getIndexRoute(location,callback){
        require.ensure([],function(require){
            callback(null,require('./components/Index'))
        })}}

getComponents(location,callback){
        require.ensure([],function(require){
            callback(null,require('./components/Course'))})}}

跳轉前確認:React Route 提供一個routerWillLeave的生命周期鈎子,使得react組件可以攔截正在發生的跳轉,或在離開route前提示用戶。

routerWillLeave 返回值有以下兩種:

1  return false 取消此次跳轉

2  return 返回提示信息,在離開route前提示用戶進行確認。

使用:1在route組件中引入 lifecycle mixin來安裝這個鈎子

import { Lifecycle } from 'react-router'

const Home = React.creactClass({

    //假設Home是一個 route 組件,使用 Lifecycle mixin 去獲取一個 routerWillLeave 方法。

    mixins:[Lifecycle],
    
    routerWillLeave(nextLocation){
        if(!this.state.isSaved)
            return 'Your work is not saved! Are you sure leave?'
    },

    .....
})

2 如果想在一個深層次嵌套的組件中使用 routerWillLeave 鈎子,只需在route組件中引入RouteContext mixin,這樣就會把route放到context中。

import { Lifecycle, RouteContext } from 'react-router'

const Home  = React.creactClass ({

        //route 會被放在Home 和它子組件及孫子組件的context中,這樣在層級樹中Home及其所有子組件都可以拿到 route。

        mixin: [ RouteContext ],

        render(){
            return <NestedForm />
        } })

const NestedForm = React.creactClass({
         //后代組件使用Lifecycle mixin 獲得 一個routerWillLeave 的方法。
        mixins:[Lifecycle],

        routerWillLeave(nextLocation){
            if(!this.state.isSave)
            return 'your work is not saved !'
        },
        ......
})

服務端渲染:

需求:放生錯誤時返回500, 需要重定向時返回30x,在渲染之前獲得數據router

方法:在<Router>API下一層使用:

1 使用 match 在渲染之前根據 location 匹配route

2 使用 RoutingContext 同步渲染 route 組件

import { renderToString } from 'react-dom/server'
import { match,RoutingContext } from 'react-router'
import routes from './routes'

serve((req,res) => {

     //這里的req.url應該是從初識請求中獲得的
    //完整的URL路徑,包括查詢字符串

    match({routes,location:req.url},{error,redirectLocation,renderProps) => {
    if(error){
        res.send(500,error.message)
        }else if (redirectLocation){
        res.redirect(302,redirectLocation.pathname + redirectLocation.search
        }else if (renderProps){
        res.send(200,renderToString(<RoutingContext {...renderProps}   //renderProps可以構建任何想要的形勢
        }else{
        res.send(404,'Not found')
        }})})

 

路由組件的生命周期中獲取數據:最簡單的方法是通過router組件的生命周期Hook來實現。

理解當路由改變時組件生命周期的變化,可以在Invoice組件里實現一個簡單的數據獲取功能

let Invoice = React.creactClass({

    getInitialState(){
        return {
            invoice:null
        }
     },

    componentDidMount(){
        //初始化數據
        this.fetchInvoice()
    },

    componentDidUpdate(prevProps){
        //通過參數更新數據
        let oldId = prevProps.params.invoiceId
        let newId = this.props.params.invoiceId
        if (newId !== oldId)
            this.fetchInvoice()
        },

    componentWillUnmount(){
        //在組件移除前 忽略正在進行中的請求
        this.ignoreLastFetch = true
        },

    fetchInvoice(){
        let url = '/api/invoices/${this.props.params.invoiceId}
        this.request = fetch(url,(err,data) => {
            if (!this.ignoreLastFetch)
                this.setState({invoice:data.invoice})
            })
},

render(){
        return <InvoiceView invoice = {this.state.invoice}/>
        }
})

組件外部跳轉:

在組件內部使用this.context.router來實現導航;

在組件外部使用Router組件上被賦予的history可以實現導航。

//main file 里renders a Router
import { Router,browserHistory } from 'react-router'
import routes from './app/routes'

render(<Router history={browserHistory} routers={routes} />.el)


//  a redux/flux action file:
import { browserHistory } from 'react-router'
browserHistory.push('/some/path')

 

瀏覽器的前進后退按鈕發生了什么????

web瀏覽器的歷史記錄相當於一個僅有入棧的棧,當用戶瀏覽器到某一個頁面時將該文檔存入到棧中,點擊「后退」或「前進」按鈕時移動指針到 history 棧中對應的某一個文檔。

  • 使用 hashchange 事件來監聽 window.location.hash 的變化
  • hash 發生變化瀏覽器會更新 URL,並且在 history 棧中產生一條記錄
  • 路由系統會將所有的路由信息都保存到 location.hash 中
  • 在 react-router 內部注冊了 window.addEventListener('hashchange', listener, false) 事件監聽器
  • listener 內部可以通過 hash fragment 獲取到當前 URL 對應的 location 對象

  在react中監聽路由hash改變,包括 瀏覽器前進回退按鈕 :componentWillReceiveProps(nextProps){if(nextProps.location.pathname != this.props.location.pathname){window.addEventListener('hashchange',listener,false)};

點擊Link后 路由系統發生????

它的 to、query、hash 屬性會被組合在一起並渲染為 href 屬性。然后調用history.pushState(state,path) ,

然后調用 window.location.hash 或者 window.history.pushState() 修改了應用的 URL


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM