react-router 還是 react-router-dom?
在 React 的使用中,我們一般要引入兩個(gè)包,react 和 react-dom,那么 react-router 和react-router-dom 是不是兩個(gè)都要引用呢?
非也,坑就在這里。他們兩個(gè)只要引用一個(gè)就行了,不同之處就是后者比前者多出了 <Link> <BrowserRouter> 這樣的 DOM 類組件。因此我們只需引用 react-router-dom 這個(gè)包就行了
react-router: 實(shí)現(xiàn)了路由的核心功能
react-router-dom: 基于react-router,加入了在瀏覽器運(yùn)行環(huán)境下的一些功能,例如:Link組件,會(huì)渲染一個(gè)a標(biāo)簽,Link組件源碼a標(biāo)簽行; BrowserRouter和HashRouter組件,前者使用pushState和popState事件構(gòu)建路由,后者使用window.location.hash和hashchange事件構(gòu)建路由。
react-router-dom依賴react-router,所以我們使用npm安裝依賴的時(shí)候,只需要安裝相應(yīng)環(huán)境下的庫(kù)即可,不用再顯式安裝react-router。基于瀏覽器環(huán)境的開(kāi)發(fā),只需要安裝react-router-dom;npm會(huì)自動(dòng)解析react-router-dom包中package.json的依賴并安裝。
react-router-dom中package.json依賴:
"dependencies": {
"history": "^4.7.2",
"invariant": "^2.2.2",
"loose-envify": "^1.3.1",
"prop-types": "^15.5.4",
"react-router": "^4.2.0",
"warning": "^3.0.0"
}
React-Router4.0不允許出現(xiàn)嵌套的子路由
例如:
<Router>
<Route path="/" component={App}>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox} />
</Route>
</Router>
React-Router4.0主張將路由拆分出來(lái),不直接使用嵌套路由
源文件改為
<BrowserRouter>
<Route path="/" component={App}></Route>
</BrowserRouter>
然后在APP組件里面再次寫(xiě)入
<Switch>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox} />
<Switch>
只渲染第一個(gè)匹配的組件<Switch>: 一個(gè)路由可能同時(shí)匹配多個(gè)路徑,在<Switch>中,只渲染匹配的第一個(gè),其他的放棄。之前這是Router的默認(rèn)行為,4.0中不默認(rèn)了
在react-router 2.0中可選參數(shù)是這樣寫(xiě)的
<Route path='/index(/:hello)' />
而在react-4.0中你會(huì)驚喜的發(fā)現(xiàn)這種寫(xiě)法沒(méi)用了
要寫(xiě)成這樣
<Route path='/index/:hello?' />
后邊的問(wèn)號(hào)表示這個(gè)參數(shù)是可選的
Router變化
react-router將history分為三類。
- hashHistory 老版本瀏覽器的history
- browserHistory h5的history
- createMemoryHistory node環(huán)境下的history,存儲(chǔ)在memory中
4.0之前版本的react-router針對(duì)三者分別實(shí)現(xiàn)了createHashHistory、createBrowserHistory和create MemoryHistory三個(gè)方法來(lái)創(chuàng)建三種情況下的history,這里就不討論他們不同的處理方式了,好奇的可以去了解一下~
到了4.0版本,在react-router-dom中直接將這三種history作了內(nèi)置,于是我們看到了BrowserRouter、HashRouter、MemoryRouter這三種Router,當(dāng)然,你依然可以使用React-router中的Router,然后自己通過(guò)createHistory來(lái)創(chuàng)建history來(lái)傳入。
Route標(biāo)簽
它最基本的職責(zé)就是當(dāng)頁(yè)面的訪問(wèn)地址與 Route 上的 path 匹配時(shí),就渲染出對(duì)應(yīng)的 UI 界面。
<Route> 自帶三個(gè) render method 和三個(gè) props 。
render methods 分別是:
- <Route component>
- <Route render>
- <Route children>
每種 render method 都有不同的應(yīng)用場(chǎng)景,同一個(gè)<Route> 應(yīng)該只使用一種 render method ,大部分情況下你將使用 component 。
props 分別是:
- match
- location
- history
location對(duì)象包括:
- pathname 同window.location.pathname
- search 同window.location.search
- state 一個(gè)捆綁在這個(gè)地址上的object對(duì)象
- action PUSH, REPLACE, 或者 POP中的一個(gè)
- key 唯一ID
發(fā)現(xiàn) location.query屬性沒(méi)有了,現(xiàn)在通過(guò) 'query-string' 模塊進(jìn)行轉(zhuǎn)換獲取
import queryString from 'query-string'
let query=this.query=queryString.parse(location.search);
match 對(duì)象包含了 <Route path> 如何與 URL 匹配的信息,具有以下屬性:
match對(duì)象包括:
- params: object 路徑參數(shù),通過(guò)解析 URL 中的動(dòng)態(tài)部分獲得鍵值對(duì)
- isExact: bool 為 true 時(shí),整個(gè) URL 都需要匹配
- path: string 用來(lái)匹配的路徑模式,用于創(chuàng)建嵌套的 <Route>
- url: string URL 匹配的部分,用于嵌套的 <Link>
存: this.props.history.push({pathname:"/web/updateStaff/" + text.userId});
讀:this.props.match.params.userId
想了解更詳細(xì)的參數(shù)傳遞,可以參考 http://www.itdecent.cn/p/ad8cc02b9e6c
BrowserRouter和HashRouter區(qū)別
hashHistory使用 URL 中的 hash(#)部分去創(chuàng)建路由,舉例來(lái)說(shuō),用戶訪問(wèn)http://www.example.com/,實(shí)際會(huì)看到的是http://www.example.com/#/。
當(dāng)頁(yè)面刷新的時(shí)候,對(duì)于BrowserHistory, 瀏覽器會(huì)向后臺(tái)發(fā)送整個(gè)URL的請(qǐng)求, 而對(duì)于HashHistory, 它只會(huì)請(qǐng)求后臺(tái)的根目錄。
browserHistory 是使用 React-Router 的應(yīng)用推薦的 history方案。它使用瀏覽器中的 History API 用于處理 URL,創(chuàng)建一個(gè)像example.com/list/123這樣真實(shí)的 URL 。
在browserHistory 模式下,URL 是指向真實(shí) URL 的資源路徑,當(dāng)通過(guò)真實(shí) URL 訪問(wèn)網(wǎng)站的時(shí)候,由于路徑是指向服務(wù)器的真實(shí)路徑,但該路徑下并沒(méi)有相關(guān)資源,所以用戶訪問(wèn)的資源不存在。
當(dāng)本地使用browserHistory , 因?yàn)閣ebpack.config.js中使用 webpack-dev-server 已經(jīng)做了配置。所以不會(huì)出現(xiàn)刷新頁(yè)面404.
webpackConfig.devServer = {
contentBase: path.resolve(__dirname, 'build'),
compress: true, //gzip壓縮
historyApiFallback: true,
};
但是要想在發(fā)版后正常使用,服務(wù)器需要進(jìn)行相關(guān)路由配置,參考 (這里):
問(wèn)題解決
1.使用render加載組件后,組件加載不出來(lái)
https://blog.csdn.net/aqtata/article/details/76169974
2.為什么用 this.props.history.push({......})不起作用
用此方法不起作用說(shuō)明,你直接引用的Router路由,在ReactRouter4.x里Router里面并沒(méi)有內(nèi)置history對(duì)象,React Router 是建立在 history 之上的。 簡(jiǎn)而言之,一個(gè) history 知道如何去監(jiān)聽(tīng)瀏覽器地址欄的變化, 并解析這個(gè) URL 轉(zhuǎn)化為 location 對(duì)象, 然后 router 使用它匹配到路由,最后正確地渲染對(duì)應(yīng)的組件。所以你只能通過(guò)createHistory創(chuàng)建的自定義的history對(duì)象,并將其傳入Router傳入來(lái)實(shí)現(xiàn)路由動(dòng)態(tài)跳轉(zhuǎn)
// HTML5 history, 推薦
import createHistory from 'history/lib/createBrowserHistory'
// Hash history
import createHistory from 'history/lib/createHashHistory'
// 內(nèi)存 history (如:node環(huán)境)
import createHistory from 'history/lib/createMemoryHistory'
const history = createHistory()
......
<Router history={history }></Router>
history 一個(gè)管理js應(yīng)用session會(huì)話歷史的js庫(kù)。它將不同環(huán)境(瀏覽器,node...)的變量統(tǒng)一成了一個(gè)簡(jiǎn)易的API來(lái)管理歷史堆棧、導(dǎo)航、確認(rèn)跳轉(zhuǎn)、以及sessions間的持續(xù)狀態(tài)。
3.為什么使用IndexRoute會(huì)報(bào)錯(cuò)
因?yàn)閞eact-router4*已經(jīng)拋棄了IndexRoute
以前
<BrowserRouter>
<Route path="/" component={Frame}>
<IndexRoute component={Home} />
<Route path="/detail" component={Detail}></Route>
</Route>
</BrowserRouter>
現(xiàn)在的默認(rèn)路由為
<BrowserRouter>
<Frame>
<Route path="/" exact component={Home}/>
<Route path="/detail" component={Detail}></Route>
</Frame>
</BrowserRouter>