標籤:
序
現在用react寫單頁應用基本上都是用react-router做前端路由了吧!最近在使用react-router的過程中遇到了不少問題,在這裡總結一下。
瀏覽器url
react-router預設提供的history是 createHashHistory ,即它用到的是 URL 中的 hash(#
)部分去建立形如 example.com/#/some/path
的路由,所以你會看到url多了類似 _key=s1gvrm 的 query,這真的很難看。而且這也不是官方在實際生產應用中所推薦的。要改變這種情況的話,我們需要去使用 createBrowserHistory ,在我們的代碼中引入history,並在Router組件處調用createBrowserHistory
方法即可。
import React from "react";import ReactDOM from "react-dom";import createBrowserHistory from "history/lib/createBrowserHistory"import { Router,Route,Link,browserHistory,IndexRoute,IndexLink } from "react-router";class App extends React.Component{ render(){ return( ... ); }};ReactDOM.render(( <Router history={ createBrowserHistory() }> ... </Router> ),document.getElementById("app"));
其實關於url還有許多的細節,因為react-router本身就是構建於history之上的。單頁應用的url只不過是針對於react-router的一個標示而已,介面間的跳轉全然由react-router決定,react-router檢查當前url隨後渲染匹配的路由群組件,所以在瀏覽器上直接輸入一個正確的非根路徑你甚至只能看到404。
組件通訊
這是一個用react寫代碼永遠都繞不開的話題。react-router是基於react開發的,所以它的每一個route都是一個組件。路由群組件間的通訊一般藉由Link來實現,而根據路由參數的不同,還可以分成兩種。這個很容易理解,因為這兩種方式和我們平時寫的後台路由並沒有什麼太大差別。
1 param,param通過/:param的方式傳遞。
比如說我們現在有一個顯示訊息列表的路由群組件,我們需要在點擊每一個訊息的時候能跳轉到顯示被點擊訊息詳情的路由群組件。這個時候我們訊息詳情路由群組件可以是這樣定義的:
<Route path="News_detail/:news_id" component={ news_detail }/>
在訊息列表路由群組件那裡我們讓每一條訊息都是這樣的一個Link:
<Link to={ `News_detail/${ element.timestamp }` } >{ element.news }</Link>
這樣的話我們的訊息詳情組件就能通過 this.props.params 擷取到訊息列表組件傳遞而來的 element.timestamp 參數了。
2 query
<Link to="/Activity_Publish" query={{ timestamp : element.timestamp }}>編輯</Link>
在 /Activity_Publish 映射的路由群組件裡面可以通過
var { query } = this.props.location;var timestamp = query.timestamp;
擷取到query參數。
相對於param,局限性更小,你可以根據需要傳遞更多的參數,只不過有點類似於get請求,傳遞的參數會附帶在url後面,看起來有點醜,而且幾乎無隱蔽性可言。
3 state
不過還是有第三種方式的,就是state,這種方式藉助了location 對象,location 對象
可以簡單的認為是 url 的對象形式表示,這裡要提的是 location.state
,每個 URL 都會對應一個 state 對象,你可以在對象裡儲存資料,但這個資料卻不會出現在 url 中。實際上,資料被存在了 sessionStorage 中,所以這種方式簡直就是query的加強版。
<Link to="/Activity_Publish" state={{ timestamp : element.timestamp }}>編輯</Link>
按需載入
react-router協同webpack的使用可以實現組件的按需載入,而且這種按需載入完全是非同步,這點特別酷炫,你不再需要一口氣載入那麼大的js檔案,即使裡麵包含著許多使用者甚至都不會使用到的web組件。你可以只根據需要載入使用者瀏覽的那些組件,這個舉措將會幫你大大的降低首屏渲染的時間。
實現這個功能很簡單,比如在一開始你的路由是這樣子的:
...import News_detail from "./marriage_component/activity/news_detail.jsx";...class App extends React.Component{ render(){ ... }};ReactDOM.render(( <Router history={ createBrowserHistory() }> <Route path="/marriage_app" component={ App }> ... <Route path="/marriage_app/News_detail/:news_id" component={ News_detail }/> ...
把它改成這樣就行了:
...//import News_detail from "./marriage_component/activity/news_detail.jsx";...class App extends React.Component{ render(){ ... }};ReactDOM.render(( <Router history={ createBrowserHistory() }> <Route path="/marriage_app" component={ App }> ... <Route path="/marriage_app/News_detail/:news_id" getComponent={ (nextState, callback) =>{ require.ensure( [ ], (require) => { callback(null, require("./marriage_component/activity/news_detail").default) }) } }/> ...
一開始的組件不再需要被匯入,webpack會幫你在需要的時候引入它。
最後
這種前後端分離的模式讓我們團隊的後台特別開心,不過其實他不知道,這種前端掌控一切的感覺也讓我很得意啊哈哈,以後誰再說我切圖仔我跟誰急。
記、react-router