為了追求極致的使用者體驗,很多Web應用採用單頁面方式呈現,然而單頁面應用,往往對應著高複雜度,比如多層次路由配置、統一資料處理等,這需要專案有一個強大的技術架構和友好的構建環境來支撐。路由器,作為單頁面構建的基礎,對單頁面應用的開發、載入、執行各個環節都起著至關重要的作用,專案體量越大,對路由器的依賴表現越強。
下面是一個React應用的基礎路由配置,瞭解React的同學一定不陌生:
1 2 3 4 5 6 7 8 9 10 11 12 |
const App = ()=> { return ( <HashRouter> <div> <Route cache component={ Home } path="/"/> <Route component={ Products } path="/products"/> </div> </HashRouter> ) } ReactDOM.render(<App/>, document.getElementById('root')) |
是啊,路由配置不就這麼簡單嗎?
真正做過單頁面應用的同學要反駁你了,並且會立刻提出很多問題:
- 路由配置拆分怎麼做?
- 動態載入怎麼做?
- props怎麼傳遞?
- 登入攔截怎麼做?
- 列表頁能不能快取?
- balabala……
能遇到這些問題的同學,相信一定是飽經風霜了。這些問題,Demo中是不會有的,都是真實專案中才能遇到的。
當然,這篇文章,就是為解決這些問題而生的,下面我們以React-Keeper(以下簡稱Keeper)為例,來解決這些問題。
BTW: React-Keeper是React生態裡一款較新的開源路由庫,由國內團隊開發,借鑑了React-Router 4很多特點,不過靈活性、實用性都強於React-Router很多,而且相容React-Router常用用法,其文件和程式碼可以參見React-Keeper GitHub官網。
1. 路由拆分
集中化的路由配置是一個很糟糕的方案,尤其是在大型Web應用中,路由拆分是很有必要的。
Keeper實現路由拆分的方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
const App = ()=> { return ( <HashRouter> <div> <Route cache component={ Home } path="/"/> <Route component={ Products } path="/products"/> </div> </HashRouter> ) } const Products = ()=> { return ( <div> <Route component={ ScienceProducts } path="/sci" /> <Route component={ DailiUseProducts } path="/dai" /> </div> ) } ReactDOM.render(<App/>, document.getElementById('root')) |
實際開發中可以將大量的路由配置資訊,按照模組化的方式進行拆分,跟路由只引入模組入口,內部頁面配置在模組內部,模組內可以再切分二級模組,以此實現路由的拆分。
2. 動態載入
把所有的JS檔案打包為一個檔案並不是一個明智的選擇,這樣會嚴重拖慢首屏的載入時間,JS程式碼應該是分割的,並且是按需載入的。
Keeper實現按需載入的方式:
1 2 3 4 5 6 7 8 9 |
// 定義動態載入函式 const loadProduct = (cb)=> { System.import('../Products.js').then((Products)=>{ cb(Products) }) } // 通過loadComponent屬性引入 <Route loadComponent={ loadProduct } path='/products'/> |
3. props傳遞
我們知道在React-Router中並不支援自定義props的傳遞,然而這在Keeper中支援得很好:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
let hostUser = { id: 'ASDFSDFG', name: '馬化騰' } // 父元件中通過props傳入Route (hostUser) const Products = ()=> { return ( <div> <Route hostUser={ hostUser } component={ ScienceProducts } path="/sci" /> <Route component={ DailiUseProducts } path="/dai" /> </div> ) } // Route元件所有的props自動傳入子元件 const ScienceProducts = (props)=> { return ( <div> <h3>{ props.hostUser.name }</h3> </div> ) } |
4. 登入攔截
登入攔截、許可權檢測、表單關閉檢測,這些是業務中非常常見的場景,而這也在Keeper中得到了很好的支援。
Keeper提供了兩種過濾器來對路由的狀態變化進行過濾和攔截:EnterFilter和LeaveFilter。
EnterFilter: 進入頁面之前執行的過濾器,適用於登入檢測、許可權檢測一類的場景。
LeaveFilter: 頁面解綁之前執行的過濾器,適用於表單關閉檢測一類的場景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// 定義過濾器,內部通過callback進行流程控制 const loginFilter = (callback, props)=> { if(!props.host) { new Promise((resolve, reject)=>{ // some code }).then(callback); } } // 將過濾器加入Route <HashRouter> <Route path='/user' component={User} enterFilter={ loginFilter } /> </HashRouter> // 多過濾器配置 <HashRouter> <Route path='/user' component={User}, enterFilter={[ loginFilter, permitFilter1, permitFilter2 ] } /> </HashRouter> |
5. 進階
Keeper提供了很靈活的配置方式,以讓我們簡單的寫出優雅的程式碼。從下面看幾個場景切入介紹下Keeper常用配置的使用。
Q1: 頁面未找到時顯示預設
A1: 使用Route提供的miss屬性,當頁面找不到的時候自動渲染該元件。
1 |
<Route miss path='/home' component={ Home }/> |
Q2: 進入一個模組直接進入模組引導頁
A2: 使用Route提供的index屬性,和miss使用方式雷同,並且可以和miss一起使用。
1 |
<Route index miss path='/home' component={ Home }/> |
Q3: 元件地址重定向的處理
A3: 使用Route提供的redirect屬性,當其他條件匹配完成時,自動進行頁面重定向。
1 |
<Route redirect='/homepage' path='/home' component={ Home }/> |
Q4: 如何使用history的state屬性?
A4: Keeper內部整合了state代理,對支援state API的瀏覽器,直接使用state API;對其他瀏覽器使用內部整合的state管理器,即使用隨機ID(URL中加入隨機key)來對映state,並使用sessionStorage進行儲存。
寫在最後
React-Keeper是一款新興的React路由庫,由於其靈活的設計和強大的實用功能,一經發布便引起眾多React開發者關注與嘗試。
React-Keeper剛剛釋出了V2.0版本,在底層很多地方做了優化。不過新興框架,文件還不健全,目前開發者的使用方式,都是依賴其GitHub官網文件,目前尚未有中文文件。
一句話點評React-Keeper: 學習自React-Router,卻遠超過React-Router。