最近在學習react,在路由這一塊有點看不懂,第一感覺是靈活性很大,想怎么來就怎么來,但問題也來了,稍微復雜一點就GG了,不如vue的傻瓜式配置來的方便。
先說一下vue的路由配置方式,目錄結構如下(簡化了結構)
━ src├━ App.vue├━ layout.vue├━ router.js┕━ main.js
main.js
的內容是官方標配,沒什么好說的,引入路由配置并加載
import router from './router' // 引入路由配置
import App from './App.vue'
new Vue({router, // 加載路由配置render: h => h(App)
}).$mount('#app')
App.vue
中添加一個router-view
作為一級路由視圖
<template><div id="app"><router-view/></div>
</template>
router.js
書寫路由配置
import Layout from './layout'
export default new VueRouter({mode: 'history',base: process.env.BASE_URL,routes: [{path: '/',component: Layout,children: [{path: 'about',component: () => import('./About.vue')},{path: 'about2',component: () => import('./About2.vue')}]},{path: '/404',name: '404',component: () => import('./404.vue')}]
})
layout.vue
布局文件,中間添加一個router-view
作為二級路由視圖
<template><div class="layout-container"><header><router-link to="/">Home</router-link><router-link to="/about">About</router-link><router-link to="/about2">About2</router-link><router-link to="/404">404</router-link></header><router-view class="layout-content"></router-view><footer></footer></div>
</template>
簡單的說一下,
App.vue
就是根元素,路徑/
和/404
都將對應路由的組件渲染在App中的router-view
位置,分別是layout.vue
和404.vue
;
路徑/
下的子路由about
和about2
對應的完整路徑分別為/about
和/about2
,當匹配這兩個路徑時,首先會在App
根元素下渲染一級路由的組件,即layout.vue
,然后再在一級路由組件(layout.vue
)中的router-view
位置渲染二級路由組件。
現在來看一下react-router
的工作方式,一個簡單的路由如下(用的是react-router-dom
,)
修改App.js
,使用了Switch
包裹,表示只渲染第一個匹配路由的組件
import React from 'react';
import { BrowserRouter, Route, Link } from "react-router-dom";const Layout = props => (<div className="layout-container"><header><Link to='/'>Home</Link><Link to='/about'>About</Link><Link to='/about2'>About2</Link><Link to='/404'>404</Link></header>{props.children}<footer></footer></div>
)
const About = props => (<div>this is About Page</div>
)
const About2 = props => (<div>this is About2 Page</div>
)
const Page404 = props => (<div>this is 404 Page <Link to="/">GO HOME</Link></div>
)const App = props => (<BrowserRouter><Switch><Route path='/404' component={Page404}></Route><Layout><Route path="about" component={About}></Route></Layout></Switch></BrowserRouter>
)
export default App;
對比vue,react-router一個很明顯的區別就是路由是直接寫在組件中的,這繼承了react的核心思想,一切皆為組件。
其實仔細想想,從感官層面來講,vue-router中的router-view也是一個特殊的組件,功能有點類似vue的動態組件<component />
,通過匹配地址與路由,將對應的組件替渲染出來;react-router也是如此,有了Switch
,react-router將匹配到的唯一路由對應的組件渲染出來,這樣一想,兩者其實很相似,區別在于vue將這一過程在內部封裝簡化了,而react則顯式的需要我們手動去書寫這一過程。
調試react-router可以發現,在404頁面和home頁面之間切換,頁面時發生變化了的,說明路由生效,但是點擊about頁面無任何變化,這就有點惆悵了,難道不支持嵌套路由???
其實并不是,如果把404路由放到Layout下面去的話(如下更改,下面簡稱代碼2,原來的簡稱代碼1),會發現404頁面也無法切換了
// 代碼2
const App = props => (<BrowserRouter><Switch><Layout><Route path="about" component={About}></Route></Layout><Route path='/404' component={Page404}></Route></Switch></BrowserRouter>
)
這是因為使用了Switch
,它只會渲染第一個匹配的組件,那么代碼2中不管匹配到什么地址,Switch
在渲染了Layout
后就不在渲染其他的路由對應的組件了,那么加一層路由地址呢???(如下代碼3)
const App = props => (<BrowserRouter><Switch><Route path='/'><Layout><Route path='about' component={About}></Route></Layout></Route><Route path='/404' component={Page404}></Route></Switch></BrowserRouter>
結果還是不起作用,通過react-dev-tool
發現,內部的路由組件根本沒有發生變化,其實到這里問題就已經很明顯了,加上之前的分析,react復雜路由之所以不生效就是因為路由匹配問題,不管是/404
還是/about
,在代碼3這種寫法下,路由匹配到<Route path='/'>
這里的時候就截至了,不會再往下或往后繼續匹配,這讓我想起了ThinkPHP的路由,需要將靜態路由和長路由寫在前面,或者添加截至符號。react-router可以通過Route
的exact
屬性來達到完全匹配的效果。代碼修改如下(代碼4)
const App = props => (<BrowserRouter><Switch><Route exact path='/' component={Layout}></Route><Route path='/404' component={Page404}></Route><Layout><Route path='/about' component={About}></Route><Route path='/about2' component={About2}></Route></Layout></Switch></BrowserRouter>
)
代碼4可以實現4個頁面的切換,效果和vue一致。
總結:react的路由配置和vue相比,還是有很大區別的,vue的嵌套路由比較直觀,書寫也很方便,react的路由配置更貼近于傳統的路由配置方式。官方倒是有嵌套路由的案例,但是那個還沒有弄懂,代碼調試不通過,我看的那個應該是舊版的文檔,可能不適用新版的react-router。