記、基於react-router的單頁應用


現在用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隨后渲染匹配的路由組件,因為是前端路由,所以如果直接在瀏覽器上輸入相對應的組件url,而后端卻不對此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

這種方式借助了location 對象,location 對象可以簡單的認為是 url 的對象形式表示,這里要提的是 location.state,每個 URL 都會對應一個 state 對象,你可以在對象里存儲數據,但這個數據卻不會出現在 url 中。實際上,數據被存在了 sessionStorage 中,舊的路由組件可以借助這種方式傳遞數據給新的路由組件,但是會有個問題就是,新的路由組件雖然在首次被渲染的時候可以成功拿到數據,但是如果此時瀏覽器被刷新的話,傳遞過來的數據也會消失。

<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會幫你在需要的時候引入它。

最后

這種前后端分離的模式真的很贊,但似乎對SEO並不是很友好。如果真的需要SEO,又追求於實現前后端的真正解耦,是不是以Nodejs為中間層的架構模式會成為一種解決方案呢?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM