React Router v4 發佈已經有幾個月了,但好像並無獲得太多人的青睞,你們(包括咱們團隊本身)仍是習慣使用v二、v3版本。這一方面是由於v4版本是一次破壞性的升級,從v二、v3 升級到v4,必須要大量重寫原有的路由相關的代碼,對於已經穩定的項目,通常是不會輕易嘗試這種變動的;另外一方面,即便是新項目,不少開發者也依然選擇使用v二、v3老版本,由於v4新的設計思想,意味着你必須改變原有的使用路由的思惟,才能正確的使用新版本。前端
React Router v4 最大的變動,不是API的變動,而是從靜態路由到動態路由的變化。什麼是靜態路由呢?靜態路由是一堆在應用運行前就已經定義好的路由配置,應用須要在啓動時,加載這些配置,構建出整個應用的路由表,而後當接收到某一請求時,根據請求地址,到應用路由表中找到對應的處理頁面或處理方法。不論是前端開發,仍是後端開發,只要涉及到路由,大部分狀況下,其實咱們使用的都是靜態路由。例如,React Router v3版本中,咱們會配置一個相似下面形式的路由:react
<Router history={browserHistory}> <Route path='/' component={App}> <Route path='about' component={About}> <Route path='contact' component={Contact}> // ... </Route> </Router>
它的基本工做流程是:Router組件根據全部的子組件Route,生成全局的路由表,路由表中記錄了path與UI組件的映射關係,而後Router監聽path的變化,當path變化時,根據新的path,找出對應所需的全部UI組件,按必定層級將這些UI組件渲染出來。後端
對於已經很熟悉靜態路由使用方式的開發者來講,上面的工做流程顯得很天然,理解起來也絕不費力。既然如此,React Router的做者爲何還要把這一切推翻呢?緣由是React Router不是普通的Router,它是「React」的Router。React致力於提供一個高效簡潔的組件化方案,組件就是React的核心,在React的設計思想中,一切皆是組件。那麼什麼是組件呢?組件定義的是界面上一個區域的UI及UI的交互行爲,關注點是UI。如今讓咱們回頭來看看上面靜態路由的例子,是否是感受到什麼奇怪的地方呢?雖然Route形式上是React組件,但它其實與UI無任何關係,它只是披着React組件的外衣,提供了一條路由配置項而已。咱們也能夠從Route源碼中看出這一點:框架
const Route = createReactClass({ // 省略無關代碼 /* istanbul ignore next: sanity check */ render() { invariant( false, '<Route> elements are for router configuration only and should not be rendered' ) } })
Route的render方法中,沒有作任何UI渲染相關的工做,這確實不是一個正宗的React組件。固然你也能夠用React Router的另外一種配置路由的方式:組件化
const routes = { path: '/', component: App, childRoutes: [ { path: 'about', component: About, }, { path: 'contact', component: Contact, }, // ... ] } <Router history={browserHistory} routes={routes} />
如今你又能夠義正詞嚴的說,我沒有使用Route這個僞組件了,此次和React的設計思想沒有衝突了吧?好吧,讓咱們再來看看其餘部分。React Router v3提供了不少相似生命週期方法的API,例如onEnter, onUpdate, and onLeave ,用來爲處於不一樣階段的路由提供鉤子方法。可是,請不要忘了,React組件自己已經有一套很完善的生命週期方法了,若是一個Route就是一個組件,那麼咱們徹底能夠直接利用組件的生命週期方法,來做爲路由不一樣階段的鉤子方法。例如,咱們可使用componentDidMount 或 componentWillMount替代onEnter,使用 componentDidUpdate或 componentWillUpdate 替代onUpdate,使用componentWillUnmount替代onLeave。this
React Router v二、v3的問題,是在React組件思想以外,設計了一套API,是一種侵入式的設計。React Router的做者意識到了這個問題,因此在v4中,對React Router 進行了重寫,將Route做爲普通React組件看待,每一個Route也負責UI的渲染工做,讓React Router在React的大框架下運轉。咱們用v4版本實現上面的例子:url
<BrowserRouter> <div> <Route path='/' component={App} /> <Route path={'/about'} component={About} /> <Route path={'/contact'} component={Contact} /> </div> </BrowserRouter>
但從表面上看,並不能很直觀地看出Route工做機制的變化。這裏作一簡單說明:Route的做用不是提供路由配置,而是一個普通的UI組件,無論請求的路徑是什麼,Route組件老是會被渲染,只不過在Route內部會判斷請求路徑是否與當前的path匹配,若是匹配,就會把Route component屬性指向的組件做爲子組件渲染出來,若是不匹配,會渲染一個null。能夠重新版Route 的render方法源碼中印證這個流程:spa
class Route extends React.Component { //...省略無關代碼 render() { const { match } = this.state const { children, component, render } = this.props const { history, route, staticContext } = this.context.router const location = this.props.location || route.location const props = { match, location, history, staticContext } return ( component ? ( // component prop gets first priority, only called if there's a match match ? React.createElement(component, props) : null ) : render ? ( // render prop is next, only called if there's a match match ? render(props) : null ) : children ? ( // children come last, always called typeof children === 'function' ? ( children(props) ) : !Array.isArray(children) || children.length ? ( // Preact defaults to empty children array React.Children.only(children) ) : ( null ) ) : ( null ) ) } }
這種模式的路由就是動態路由。可見,動態路由發揮做用的時間是在組件渲染時,而不是經過提早配置的方式,在應用剛收到請求時,就已經知道該渲染哪些組件了。設計
從上面的分析,能夠得出動態路由的一個優勢是,它會同時負責UI的渲染工做,而不是單純的路由配置工做。此外,動態路由的另一個優勢是,你能夠在任意時間、任意地點自由添加新的Route。例如,在上面的例子中,我想在About組件內定義兩個新的路由,能夠這麼作:code
<BrowserRouter> <div> <Route path='/' component={App} /> <Route path={'/about'} component={About} /> <Route path={'/contact'} component={Contact} /> </div> </BrowserRouter> const About = (props) => ( <div> <Route path={`${props.match.url}/a`} component={AboutA} /> <Route path={`${props.match.url}/b`} component={AboutB} /> </div> )
這樣,當訪問 /about/a 時,組件AboutA 會被做爲About的子組件渲染,當訪問 /about/b 時,組件AboutB 會做爲About的子組件渲染。並且,/about/a 和 /about/b 咱們是直接定義到 About 組件內的,並不須要像靜態路由那樣作集中配置,充分體現了動態路由的靈活性。
總結一下,雖然React Router v4 重構了路由使用的思想,但卻和React的設計思想更加切合,我的認爲是一個巨大的進步。使用React Router v4 時,你須要忘掉之前使用靜態路由的思惟方式,把路由當成普通組件看待,習慣了這個思惟轉變後,你就會發現React Router v4的魅力所在了。
歡迎關注個人公衆號:老幹部的大前端,領取21本大前端精選書籍!