自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

ReactRouter-V4 構(gòu)建之道與源碼分析

開(kāi)發(fā) 開(kāi)發(fā)工具
本文即是我在構(gòu)建 React Router V4 過(guò)程中的考慮以及所謂路由即組件思想的落地實(shí)踐。

[[188988]]

多年之后當(dāng)我回想起初學(xué)客戶端路由的那個(gè)下午,滿腦子里充斥著的只是對(duì)于單頁(yè)應(yīng)用的驚嘆與漿糊。彼時(shí)我還是將應(yīng)用代碼與路由代碼當(dāng)做兩個(gè)獨(dú)立的部分進(jìn)行處理,就好像同父異母的兄弟盡管不喜歡對(duì)方但是不得不在一起。幸而這些年里我能夠和其他優(yōu)秀的開(kāi)發(fā)者進(jìn)行交流,了解他們對(duì)于客戶端路由的看法。盡管他們中的大部分與我“英雄所見(jiàn)略同”,但是我還是找到了合適的平衡路由的抽象程度與復(fù)雜程度的方法。本文即是我在構(gòu)建 React Router V4 過(guò)程中的考慮以及所謂路由即組件思想的落地實(shí)踐。首先我們來(lái)看下我們?cè)跇?gòu)建路由過(guò)程中的測(cè)試代碼,你可以用它來(lái)測(cè)試你的自定義路由:

  1. const Home = () => ( 
  2.   <h2>Home</h2> 
  3.  
  4. const About = () => ( 
  5.   <h2>About</h2> 
  6.  
  7. const Topic = ({ topicId }) => ( 
  8.   <h3>{topicId}</h3> 
  9.  
  10. const Topics = ({ match }) => { 
  11.   const items = [ 
  12.     { name'Rendering with React', slug: 'rendering' }, 
  13.     { name'Components', slug: 'components' }, 
  14.     { name'Props v. State', slug: 'props-v-state' }, 
  15.   ] 
  16.  
  17.   return ( 
  18.     <div> 
  19.       <h2>Topics</h2> 
  20.       <ul> 
  21.         {items.map(({ name, slug }) => ( 
  22.           <li key={name}> 
  23.             <Link to={`${match.url}/${slug}`}>{name}</Link> 
  24.           </li> 
  25.         ))} 
  26.       </ul> 
  27.       {items.map(({ name, slug }) => ( 
  28.         <Route key={name} path={`${match.path}/${slug}`} render={() => ( 
  29.           <Topic topicId={name} /> 
  30.         )} /> 
  31.       ))} 
  32.       <Route exact path={match.url} render={() => ( 
  33.         <h3>Please select a topic.</h3> 
  34.       )}/> 
  35.     </div> 
  36.   ) 
  37.  
  38. const App = () => ( 
  39.   <div> 
  40.     <ul> 
  41.       <li><Link to="/">Home</Link></li> 
  42.       <li><Link to="/about">About</Link></li> 
  43.       <li><Link to="/topics">Topics</Link></li> 
  44.     </ul> 
  45.  
  46.     <hr/> 
  47.  
  48.     <Route exact path="/" component={Home}/> 
  49.     <Route path="/about" component={About}/> 
  50.     <Route path="/topics" component={Topics} /> 
  51.   </div> 

如果你對(duì)于 React Router v4 尚不是完全了解,我們先對(duì)上述代碼中涉及到的相關(guān)關(guān)鍵字進(jìn)行解釋。Route 會(huì)在當(dāng)前 URL 與 path 屬性值相符的時(shí)候渲染相關(guān)組件,而 Link 提供了聲明式的,易使用的方式來(lái)在應(yīng)用內(nèi)進(jìn)行跳轉(zhuǎn)。換言之,Link 組件允許你更新當(dāng)前 URL,而 Route 組件則是根據(jù) URL 渲染組件。本文并不專注于講解 RRV4 的基礎(chǔ)概念,你可以前往官方文檔了解更多知識(shí);本文是希望介紹我在構(gòu)建 React Router V4 過(guò)程中的思維考慮過(guò)程,值得一提的是,我很欣賞 React Router V4 中的 Just Components 概念,這一點(diǎn)就不同于 React Router 之前的版本中將路由與組件隔離來(lái)看,而允許了路由組件像普通組件一樣自由組合。相信對(duì)于 React 組件相當(dāng)熟悉的開(kāi)發(fā)者絕不會(huì)陌生于如何將路由組件嵌入到正常的應(yīng)用中。

Route

我們首先來(lái)考量下如何構(gòu)建Route組件,包括其暴露的 API,即 Props。在我們上面的示例中,我們會(huì)發(fā)現(xiàn)Route組件包含三個(gè) Props:exact、path 以及 component。這也就意味著我們的propTypes聲明如下:

  1. static propTypes = { 
  2.   exact: PropTypes.bool, 
  3.   path: PropTypes.string, 
  4.   component: PropTypes.func, 

這里有一些微妙的細(xì)節(jié)需要考慮,首先對(duì)于path并沒(méi)有設(shè)置為必須參數(shù),這是因?yàn)槲覀冋J(rèn)為對(duì)于沒(méi)有指定關(guān)聯(lián)路徑的Route組件應(yīng)該自動(dòng)默認(rèn)渲染。而component參數(shù)也沒(méi)有被設(shè)置為必須是因?yàn)槲覀兲峁┝似渌姆绞竭M(jìn)行渲染,譬如render函數(shù):

  1. <Route path='/settings' render={({ match }) => { 
  2.   return <Settings authed={isAuthed} match={match} /> 
  3. }} /> 

render 函數(shù)允許你方便地使用內(nèi)聯(lián)函數(shù)來(lái)創(chuàng)建 UI 而不是創(chuàng)建新的組件,因此我們也需要將該函數(shù)設(shè)置為 propTypes:

  1. static propTypes = { 
  2.   exact: PropTypes.bool, 
  3.   path: PropTypes.string, 
  4.   component: PropTypes.func, 
  5.   render: PropTypes.func, 

在確定了 Route 需要接收的組件參數(shù)之后,我們需要來(lái)考量其實(shí)際功能;Route 核心的功能在于能夠當(dāng) URL 與 path 屬性相一致時(shí)執(zhí)行渲染操作?;谶@個(gè)論斷,我們首先需要實(shí)現(xiàn)判斷是否匹配的功能,如果判斷為匹配則執(zhí)行渲染否則返回空值。我們?cè)谶@里將該函數(shù)命名為 matchPatch,那么此時(shí)整個(gè) Route 組件的 render 函數(shù)定義如下:

  1. class Route extends Component { 
  2.   static propTypes = { 
  3.     exact: PropTypes.bool, 
  4.     path: PropTypes.string, 
  5.     component: PropTypes.func, 
  6.     render: PropTypes.func, 
  7.   } 
  8.  
  9.   render () { 
  10.     const { 
  11.       path, 
  12.       exact, 
  13.       component, 
  14.       render, 
  15.     } = this.props 
  16.  
  17.     const match = matchPath( 
  18.       location.pathname, // global DOM variable 
  19.       { path, exact } 
  20.     ) 
  21.  
  22.     if (!match) { 
  23.       // Do nothing because the current 
  24.       // location doesn't match the path prop. 
  25.  
  26.       return null 
  27.     } 
  28.  
  29.     if (component) { 
  30.       // The component prop takes precedent over the 
  31.       // render method. If the current location matches 
  32.       // the path prop, create a new element passing in 
  33.       // match as the prop. 
  34.  
  35.       return React.createElement(component, { match }) 
  36.     } 
  37.  
  38.     if (render) { 
  39.       // If there's a match but component 
  40.       // was undefined, invoke the render 
  41.       // prop passing in match as an argument. 
  42.  
  43.       return render({ match }) 
  44.     } 
  45.  
  46.     return null 
  47.   } 

現(xiàn)在的 Route 看起來(lái)已經(jīng)相對(duì)明確了,當(dāng)路徑相匹配的時(shí)候才會(huì)執(zhí)行界面渲染,否則返回為空?,F(xiàn)在我們?cè)倩剡^(guò)頭來(lái)考慮客戶端路由中常見(jiàn)的跳轉(zhuǎn)策略,一般來(lái)說(shuō)用戶只有兩種方式會(huì)更新當(dāng)前 URL。一種是用戶點(diǎn)擊了某個(gè)錨標(biāo)簽或者直接操作 history 對(duì)象的 replace/push 方法;另一種是用戶點(diǎn)擊前進(jìn)/后退按鈕。無(wú)論哪一種方式都要求我們的路由系統(tǒng)能夠?qū)崟r(shí)監(jiān)聽(tīng) URL 的變化,并且在 URL 發(fā)生變化時(shí)及時(shí)地做出響應(yīng),渲染出正確的頁(yè)面。我們首先來(lái)考慮下如何處理用戶點(diǎn)擊前進(jìn)/后退按鈕。React Router 使用 History 的 .listen 方法來(lái)監(jiān)聽(tīng)當(dāng)前 URL 的變化,其本質(zhì)上還是直接監(jiān)聽(tīng) HTML5 的 popstate 事件。popstate 事件會(huì)在用戶點(diǎn)擊某個(gè)前進(jìn)/后退按鈕的時(shí)候觸發(fā);而在每次重渲染的時(shí)候,每個(gè) Route 組件都會(huì)重現(xiàn)檢測(cè)當(dāng)前 URL 是否匹配其預(yù)設(shè)的路徑參數(shù)。

  1. class Route extends Component { 
  2.   static propTypes: { 
  3.     path: PropTypes.string, 
  4.     exact: PropTypes.bool, 
  5.     component: PropTypes.func, 
  6.     render: PropTypes.func, 
  7.   } 
  8.  
  9.   componentWillMount() { 
  10.     addEventListener("popstate", this.handlePop) 
  11.   } 
  12.  
  13.   componentWillUnmount() { 
  14.     removeEventListener("popstate", this.handlePop) 
  15.   } 
  16.  
  17.   handlePop = () => { 
  18.     this.forceUpdate() 
  19.   } 
  20.  
  21.   render() { 
  22.     const { 
  23.       path, 
  24.       exact, 
  25.       component, 
  26.       render, 
  27.     } = this.props 
  28.  
  29.     const match = matchPath(location.pathname, { path, exact }) 
  30.  
  31.     if (!match) 
  32.       return null 
  33.  
  34.     if (component) 
  35.       return React.createElement(component, { match }) 
  36.  
  37.     if (render) 
  38.       return render({ match }) 
  39.  
  40.     return null 
  41.   } 

你會(huì)發(fā)現(xiàn)上面的代碼與之前的相比多了掛載與卸載 popstate 監(jiān)聽(tīng)器的功能,其會(huì)在組件掛載時(shí)添加一個(gè) popstate 監(jiān)聽(tīng)器;當(dāng)監(jiān)聽(tīng)到 popstate 事件被觸發(fā)時(shí),我們會(huì)調(diào)用 forceUpdate 函數(shù)來(lái)強(qiáng)制進(jìn)行重渲染??偨Y(jié)而言,無(wú)論我們?cè)谙到y(tǒng)中設(shè)置了多少的路由組件,它們都會(huì)獨(dú)立地監(jiān)聽(tīng) popstate 事件并且相應(yīng)地執(zhí)行重渲染操作。接下來(lái)我們繼續(xù)討論 matchPath 這個(gè) Route 組件中至關(guān)重要的函數(shù),它負(fù)責(zé)決定當(dāng)前路由組件的 path 參數(shù)是否與當(dāng)前 URL 相一致。這里還必須提下我們?cè)O(shè)置的另一個(gè) Route 的參數(shù) exact,其用于指明路徑匹配策略;當(dāng) exact 值被設(shè)置為 true 時(shí),僅當(dāng)路徑完全匹配于 location.pathname 才會(huì)被認(rèn)為匹配成功:

pathlocation.pathnameexactmatches?/one/one/twotrueno/one/one/twofalseyes

讓我們深度了解下 matchPath 函數(shù)的工作原理,該函數(shù)的簽名如下:

  1. const match = matchPath(location.pathname, { path, exact }) 

其中函數(shù)的返回值 match 應(yīng)該根據(jù)路徑是否匹配的情況返回為空或者一個(gè)對(duì)象。基于這些推導(dǎo)我們可以得出 matchPatch 的原型:

  1. const matchPath = (pathname, options) => { 
  2.   const { exact = false, path } = options 

這里我們使用 ES6 的解構(gòu)賦值,當(dāng)某個(gè)屬性未定義時(shí)我們使用預(yù)定義地默認(rèn)值,即 false。我在上文提及的 path 非必要參數(shù)的具體支撐實(shí)現(xiàn)就在這里,我們首先進(jìn)行空檢測(cè),當(dāng)發(fā)現(xiàn) path 為未定義或者為空時(shí)則直接返回匹配成功:

  1. const matchPath = (pathname, options) => { 
  2.   const { exact = false, path } = options 
  3.  
  4.   if (!path) { 
  5.     return { 
  6.       path: null
  7.       url: pathname, 
  8.       isExact: true
  9.     } 
  10.   } 

接下來(lái)繼續(xù)考慮具體執(zhí)行匹配的部分,React Router 使用了 pathToRegex 來(lái)檢測(cè)是否匹配,即可以用簡(jiǎn)單的正則表達(dá)式:

  1. const matchPath = (pathname, options) => { 
  2.   const { exact = false, path } = options 
  3.  
  4.   if (!path) { 
  5.     return { 
  6.       path: null
  7.       url: pathname, 
  8.       isExact: true
  9.     } 
  10.   } 
  11.  
  12.   const match = new RegExp(`^${path}`).exec(pathname) 
  13.  

這里使用的 .exec 函數(shù),會(huì)在包含指定的文本時(shí)返回一個(gè)數(shù)組,否則返回空值;下表即是當(dāng)我們的路由設(shè)置為 /topics/components時(shí)具體的返回:

  1. | path                    | location.pathname    | return value             | 
  2. ----------------------- | -------------------- | ------------------------ | 
  3. | `/`                     | `/topics/components` | `['/']`                  | 
  4. | `/about`                | `/topics/components` | `null`                   | 
  5. | `/topics`               | `/topics/components` | `['/topics']`            | 
  6. | `/topics/rendering`     | `/topics/components` | `null`                   | 
  7. | `/topics/components`    | `/topics/components` | `['/topics/components']` | 
  8. | `/topics/props-v-state` | `/topics/components` | `null`                   | 
  9. | `/topics`               | `/topics/components` | `['/topics']`            | 

這里大家就會(huì)看出來(lái),我們會(huì)為每個(gè) <Route> 實(shí)例創(chuàng)建一個(gè) match 對(duì)象。在獲取到 match 對(duì)象之后,我們需要再做如下判斷是否匹配:

  1. const matchPath = (pathname, options) => { 
  2.   const { exact = false, path } = options 
  3.  
  4.   if (!path) { 
  5.     return { 
  6.       path: null
  7.       url: pathname, 
  8.       isExact: true
  9.     } 
  10.   } 
  11.  
  12.   const match = new RegExp(`^${path}`).exec(pathname) 
  13.  
  14.   if (!match) { 
  15.     // There wasn't a match. 
  16.     return null 
  17.   } 
  18.  
  19.   const url = match[0] 
  20.   const isExact = pathname === url 
  21.  
  22.   if (exact && !isExact) { 
  23.     // There was a match, but it wasn't 
  24.     // an exact match as specified by 
  25.     // the exact prop. 
  26.  
  27.     return null 
  28.   } 
  29.  
  30.   return { 
  31.     path, 
  32.     url, 
  33.     isExact, 
  34.   } 

Link

上文我們已經(jīng)提及通過(guò)監(jiān)聽(tīng) popstate 狀態(tài)來(lái)響應(yīng)用戶點(diǎn)擊前進(jìn)/后退事件,現(xiàn)在我們來(lái)考慮通過(guò)構(gòu)建 Link 組件來(lái)處理用戶通過(guò)點(diǎn)擊錨標(biāo)簽進(jìn)行跳轉(zhuǎn)的事件。Link 組件的 API 應(yīng)該如下所示:

  1. <Link to='/some-path' replace={false} /> 

其中的 to 是一個(gè)指向跳轉(zhuǎn)目標(biāo)地址的字符串,而 replace 則是布爾變量來(lái)指定當(dāng)用戶點(diǎn)擊跳轉(zhuǎn)時(shí)是替換 history 棧中的記錄還是插入新的記錄?;谏鲜龅?API 設(shè)計(jì),我們可以得到如下的組件聲明:

  1. class Link extends Component { 
  2.   static propTypes = { 
  3.     to: PropTypes.string.isRequired, 
  4.     replace: PropTypes.bool, 
  5.   } 

現(xiàn)在我們已經(jīng)知道 Link 組件的渲染函數(shù)中需要返回一個(gè)錨標(biāo)簽,不過(guò)我們的前提是要避免每次用戶切換路由的時(shí)候都進(jìn)行整頁(yè)的刷新,因此我們需要為每個(gè)錨標(biāo)簽添加一個(gè)點(diǎn)擊事件的處理器:

  1. class Link extends Component { 
  2.   static propTypes = { 
  3.     to: PropTypes.string.isRequired, 
  4.     replace: PropTypes.bool, 
  5.   } 
  6.  
  7.   handleClick = (event) => { 
  8.     const { replaceto } = this.props 
  9.     event.preventDefault() 
  10.  
  11.     // route here. 
  12.   } 
  13.  
  14.   render() { 
  15.     const { to, children} = this.props 
  16.  
  17.     return ( 
  18.       <a href={to} onClick={this.handleClick}> 
  19.         {children} 
  20.       </a> 
  21.     ) 
  22.   } 

這里實(shí)際的跳轉(zhuǎn)操作我們還是執(zhí)行 History 中的抽象的 push 與 replace 函數(shù),在使用 browserHistory 的情況下我們本質(zhì)上還是使用 HTML5 中的 pushState 與 replaceState 函數(shù)。pushState 與 replaceState 函數(shù)都要求輸入三個(gè)參數(shù),首先是一個(gè)與***的歷史記錄相關(guān)的對(duì)象,在 React Router 中我們并不需要該對(duì)象,因此直接傳入一個(gè)空對(duì)象;第二個(gè)參數(shù)是標(biāo)題參數(shù),我們同樣不需要改變?cè)撝?,因此直接傳入空即?***第三個(gè)參數(shù)則是我們需要的,用于指明新的相對(duì)地址的字符串:

  1. const historyPush = (path) => { 
  2.   history.pushState({}, null, path) 
  3.  
  4. const historyReplace = (path) => { 
  5.   history.replaceState({}, null, path) 

而后在 Link 組件內(nèi),我們會(huì)根據(jù) replace 參數(shù)來(lái)調(diào)用 historyPush 或者 historyReplace 函數(shù):

  1. class Link extends Component { 
  2.   static propTypes = { 
  3.     to: PropTypes.string.isRequired, 
  4.     replace: PropTypes.bool, 
  5.   } 
  6.   handleClick = (event) => { 
  7.     const { replaceto } = this.props 
  8.     event.preventDefault() 
  9.  
  10.     replace ? historyReplace(to) : historyPush(to
  11.   } 
  12.  
  13.   render() { 
  14.     const { to, children} = this.props 
  15.  
  16.     return ( 
  17.       <a href={to} onClick={this.handleClick}> 
  18.         {children} 
  19.       </a> 
  20.     ) 
  21.   } 

組件注冊(cè)

現(xiàn)在我們需要考慮如何保證用戶點(diǎn)擊了 Link 組件之后觸發(fā)全部路由組件的檢測(cè)與重渲染。在我們上面實(shí)現(xiàn)的 Link 組件中,用戶執(zhí)行跳轉(zhuǎn)之后瀏覽器的顯示地址會(huì)發(fā)生變化,但是頁(yè)面尚不能重新渲染;我們聲明的 Route 組件并不能收到相應(yīng)的通知。為了解決這個(gè)問(wèn)題,我們需要追蹤那些顯現(xiàn)在界面上實(shí)際被渲染的 Route 組件并且當(dāng)路由變化時(shí)調(diào)用它們的 forceUpdate 方法。React Router 主要通過(guò)有機(jī)組合 setState、context 以及 history.listen 方法來(lái)實(shí)現(xiàn)該功能。每個(gè) Route 組件被掛載時(shí)我們會(huì)將其加入到某個(gè)數(shù)組中,然后當(dāng)位置變化時(shí),我們可以遍歷該數(shù)組然后對(duì)每個(gè)實(shí)例調(diào)用 forceUpdate 方法:

  1. let instances = [] 
  2.  
  3. const register = (comp) => instances.push(comp) 
  4. const unregister = (comp) => instances.splice(instances.indexOf(comp), 1) 

這里我們創(chuàng)建了兩個(gè)函數(shù),當(dāng) Route 掛載時(shí)調(diào)用 register 函數(shù),而卸載時(shí)調(diào)用 unregister 函數(shù)。然后無(wú)論何時(shí)調(diào)用 historyPush 或者 historyReplace 函數(shù)時(shí)都會(huì)遍歷實(shí)例數(shù)組中的對(duì)象的渲染方法,此時(shí)我們的 Route 組件就需要聲明為如下樣式:

  1. class Route extends Component { 
  2.   static propTypes: { 
  3.     path: PropTypes.string, 
  4.     exact: PropTypes.bool, 
  5.     component: PropTypes.func, 
  6.     render: PropTypes.func, 
  7.   } 
  8.  
  9.   componentWillMount() { 
  10.     addEventListener("popstate", this.handlePop) 
  11.     register(this) 
  12.   } 
  13.  
  14.   componentWillUnmount() { 
  15.     unregister(this) 
  16.     removeEventListener("popstate", this.handlePop) 
  17.   } 
  18.  
  19.   ... 

然后我們需要更新 historyPush 與 historyReplace 函數(shù):

  1. const historyPush = (path) => { 
  2.   history.pushState({}, null, path) 
  3.   instances.forEach(instance => instance.forceUpdate()) 
  4.  
  5. const historyReplace = (path) => { 
  6.   history.replaceState({}, null, path) 
  7.   instances.forEach(instance => instance.forceUpdate()) 

這樣的話就保證了無(wú)論何時(shí)用戶點(diǎn)擊 <Link> 組件之后,在位置顯示變化的同時(shí),所有的 <Route> 組件都能夠被通知到并且執(zhí)行重匹配與重渲染?,F(xiàn)在我們完整的路由解決方案就成形了:

  1. import React, { PropTypes, Component } from 'react' 
  2.  
  3. let instances = [] 
  4.  
  5. const register = (comp) => instances.push(comp) 
  6. const unregister = (comp) => instances.splice(instances.indexOf(comp), 1) 
  7.  
  8. const historyPush = (path) => { 
  9.   history.pushState({}, null, path) 
  10.   instances.forEach(instance => instance.forceUpdate()) 
  11.  
  12. const historyReplace = (path) => { 
  13.   history.replaceState({}, null, path) 
  14.   instances.forEach(instance => instance.forceUpdate()) 
  15.  
  16. const matchPath = (pathname, options) => { 
  17.   const { exact = false, path } = options 
  18.  
  19.   if (!path) { 
  20.     return { 
  21.       path: null
  22.       url: pathname, 
  23.       isExact: true 
  24.     } 
  25.   } 
  26.  
  27.   const match = new RegExp(`^${path}`).exec(pathname) 
  28.  
  29.   if (!match) 
  30.     return null 
  31.  
  32.   const url = match[0] 
  33.   const isExact = pathname === url 
  34.  
  35.   if (exact && !isExact) 
  36.     return null 
  37.  
  38.   return { 
  39.     path, 
  40.     url, 
  41.     isExact, 
  42.   } 
  43.  
  44. class Route extends Component { 
  45.   static propTypes: { 
  46.     path: PropTypes.string, 
  47.     exact: PropTypes.bool, 
  48.     component: PropTypes.func, 
  49.     render: PropTypes.func, 
  50.   } 
  51.  
  52.   componentWillMount() { 
  53.     addEventListener("popstate", this.handlePop) 
  54.     register(this) 
  55.   } 
  56.  
  57.   componentWillUnmount() { 
  58.     unregister(this) 
  59.     removeEventListener("popstate", this.handlePop) 
  60.   } 
  61.  
  62.   handlePop = () => { 
  63.     this.forceUpdate() 
  64.   } 
  65.  
  66.   render() { 
  67.     const { 
  68.       path, 
  69.       exact, 
  70.       component, 
  71.       render, 
  72.     } = this.props 
  73.  
  74.     const match = matchPath(location.pathname, { path, exact }) 
  75.  
  76.     if (!match) 
  77.       return null 
  78.  
  79.     if (component) 
  80.       return React.createElement(component, { match }) 
  81.  
  82.     if (render) 
  83.       return render({ match }) 
  84.  
  85.     return null 
  86.   } 
  87.  
  88. class Link extends Component { 
  89.   static propTypes = { 
  90.     to: PropTypes.string.isRequired, 
  91.     replace: PropTypes.bool, 
  92.   } 
  93.   handleClick = (event) => { 
  94.     const { replaceto } = this.props 
  95.  
  96.     event.preventDefault() 
  97.     replace ? historyReplace(to) : historyPush(to
  98.   } 
  99.  
  100.   render() { 
  101.     const { to, children} = this.props 
  102.  
  103.     return ( 
  104.       <a href={to} onClick={this.handleClick}> 
  105.         {children} 
  106.       </a> 
  107.     ) 
  108.   } 

另外,React Router API 中提供了所謂 <Redirect> 組件,允許執(zhí)行路由跳轉(zhuǎn)操作:

  1. class Redirect extends Component { 
  2.   static defaultProps = { 
  3.     push: false 
  4.   } 
  5.  
  6.   static propTypes = { 
  7.     to: PropTypes.string.isRequired, 
  8.     push: PropTypes.bool.isRequired, 
  9.   } 
  10.  
  11.   componentDidMount() { 
  12.     const { to, push } = this.props 
  13.  
  14.     push ? historyPush(to) : historyReplace(to
  15.   } 
  16.  
  17.   render() { 
  18.     return null 
  19.   } 

注意這個(gè)組件并沒(méi)有真實(shí)地進(jìn)行界面渲染,而是僅僅進(jìn)行了簡(jiǎn)單的跳轉(zhuǎn)操作。到這里本文也就告一段落了,希望能夠幫助你去了解 React Router V4 的設(shè)計(jì)思想以及 Just Component 的接口理念。我一直說(shuō) React 會(huì)讓你成為更加優(yōu)秀地開(kāi)發(fā)者,而 React Router 則會(huì)是你不小的助力。

【本文是51CTO專欄作者“張梓雄 ”的原創(chuàng)文章,如需轉(zhuǎn)載請(qǐng)通過(guò)51CTO與作者聯(lián)系】

戳這里,看該作者更多好文

責(zé)任編輯:武曉燕 來(lái)源: 51CTO專欄
相關(guān)推薦

2021-02-16 10:55:02

Nodejs模塊

2016-10-21 13:03:18

androidhandlerlooper

2021-09-08 10:47:33

Flink執(zhí)行流程

2016-11-29 09:38:06

Flume架構(gòu)核心組件

2016-11-25 13:26:50

Flume架構(gòu)源碼

2016-11-25 13:14:50

Flume架構(gòu)源碼

2020-06-04 12:15:08

Pythonkafka代碼

2009-12-22 13:36:39

Linux Sysfs

2021-08-06 15:06:09

騰訊開(kāi)源Apache

2013-06-26 10:25:39

2009-11-30 17:33:07

微軟

2022-04-05 12:59:07

源碼線程onEvent

2016-11-29 16:59:46

Flume架構(gòu)源碼

2011-03-15 11:33:18

iptables

2014-08-26 11:11:57

AsyncHttpCl源碼分析

2021-10-27 11:29:49

Linux框架內(nèi)核

2011-06-08 09:22:54

Samba

2017-10-25 13:20:43

軟件安全模型

2009-09-28 10:49:13

ITIL摩卡

2011-05-26 10:05:48

MongoDB
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)