近期困擾於SPA在ios微信調用分享SDK失敗的問題, 目前採用拿掉react-router路由,採用原始location.href的方式跳轉,臨時解決問題...html
坑終究是坑,不填不足以平民憤...node
這時候才發現react-router的升級至4.x,相比以前,多有不一樣之處,廢話很少說,先搞個API總體的摸索一番。react
對以上問題感興趣的,歡迎交流 ^_^ ios
重點分割線git
具體栗子參見:https://github.com/git-zhangsan/react-router4#readme(持續更新中)github
如下爲翻譯的中文API(水平有限,湊合看,歡迎糾正補充~)web
<BrowserRouter>ajax
使用HTML5歷史記錄API(pushState,replaceState和popstate事件)的<Router>來保持您的UI與URL同步。redux
Code:api
`
import { BrowserRouter } from 'react-router-dom' <BrowserRouter basename={optionalString} forceRefresh={optionalBool} getUserConfirmation={optionalFunc} keyLength={optionalNumber} > <App/> </BrowserRouter>
`
屬性:
- basename: string
全部locations的基本URL。若是應用程序從服務器上的子目錄提供,則須要將其設置爲子目錄。正確格式的基礎名稱應該有一個主要的斜槓,但沒有尾部斜線。
`
<BrowserRouter basename="/calendar"/> <Link to="/today"/> // renders <a href="/calendar/today">
`
- getUserConfirmation: func
用於確認導航的功能。默認使用window.confirm。
`
// this is the default behavior const getConfirmation = (message, callback) => { const allowTransition = window.confirm(message) callback(allowTransition) } <BrowserRouter getUserConfirmation={getConfirmation}/>
`
- forceRefresh: bool
若是爲true,則路由器將在頁面導航中使用全頁刷新。您可能只想在不支持HTML5歷史記錄API的瀏覽器中使用此功能。
`
const supportsHistory = 'pushState' in window.history <BrowserRouter forceRefresh={!supportsHistory}/>
`
- keyLength: number
location.key的長度。默認爲6。
`
<BrowserRouter keyLength={12}/>
`
- children: node
要呈現的單個子元素。
<HashRouter>
使用URL的哈希部分(即window.location.hash)的<Router>來保持您的UI與URL同步。
重要的提示:Hash history不支持location.key或location.state。在之前的版本中,咱們試圖減小行爲,可是有一些邊緣案例咱們沒法解決。
任何須要此行爲的代碼或插件將沒法正常工做。因爲此技術僅用於支持舊版瀏覽器,所以咱們建議您將服務器配置爲使用<BrowserHistory>。
`
import { HashRouter } from 'react-router-dom' <HashRouter> <App/> </HashRouter>
`
- basename: string
全部locations的基本URL。正確格式的基礎名稱應該有一個主要的斜槓,但沒有尾部斜線。
`
<HashRouter basename="/calendar"/> <Link to="/today"/> // renders <a href="#/calendar/today">
`
- getUserConfirmation: func
用於確認導航的功能。默認使用window.confirm。
`
// this is the default behavior const getConfirmation = (message, callback) => { const allowTransition = window.confirm(message) callback(allowTransition) } <HashRouter getUserConfirmation={getConfirmation}/>
`
- hashType: string
用於window.location.hash的編碼類型。可用值爲:
"slash": 建立一個hash值,例如:#/ and #/sunshine/lollipops
"noslash": 建立一個hash值,例如:# and #sunshine/lollipops
」hashbang「: 建立一個」ajax crawlable」 (已被谷歌棄用) 例如:#!/ and #!/sunshine/lollipops
默認值"slash"
- children: node
要呈現的單個子元素。
<Link>
在應用程序範圍提供聲明性,可訪問的導航
`
import { Link } from 'react-router-dom' <Link to="/about">About</Link>
`
- to: string
連接到的路徑名或位置。
`
<Link to="/courses"/>
`
- to: object
要連接的位置。
`
<Link to={{ pathname: '/courses', search: '?sort=name', hash: '#the-hash', state: { fromDashboard: true } }}/>
`
- replace: bool
若是爲true,單擊連接將替換歷史堆棧中的當前條目,而不是添加新條目。
`
<Link to="/courses" replace />
`
<NavLink>
一種特殊版本的<Link>,當與當前URL匹配時,將向渲染元素添加樣式屬性。
`
import { NavLink } from 'react-router-dom' <NavLink to="/about">About</NavLink>
`
- activeClassName: string
當活動時給出元素的類。默認給定類是活動的。這將與className支持相結合。
`
<NavLink to="/faq" activeClassName="selected" >FAQs</NavLink>
`
- activeStyle: object
當元素處於活動狀態時應用於元素的樣式。
`
<NavLink to="/faq" activeStyle={{ fontWeight: 'bold', color: 'red' }} >FAQs</NavLink>
`
- exact: bool
當爲true時,僅當位置匹配徹底時纔會應用活動類/樣式。
`
<NavLink
exact
to="/profile"
>Profile</NavLink>
`
- strict: bool
當爲真時,在肯定位置是否與當前網址匹配時,將考慮位置路徑名上的尾部斜線。
有關詳細信息,請參閱<Route strict>文檔。(https://reacttraining.com/core/api/Route/strict-bool)
`
<NavLink
strict
to="/events/"
>Events</NavLink>
`
- isActive: func
增長用於肯定連接是否活動的額外邏輯的功能。若是您想要更多地驗證連接的路徑名與當前URL的路徑名匹配,則應該使用這一點。
`
// 只有當事件ID爲奇數時,才考慮事件有效 const oddEvent = (match, location) => { if (!match) { return false } const eventID = parseInt(match.params.eventID) return !isNaN(eventID) && eventID % 2 === 1 } <NavLink to="/events/123" isActive={oddEvent} >Event 123</NavLink>
`
- location: object
isActive比較當前的歷史位置(一般是當前的瀏覽器URL)。要與其餘位置進行比較,能夠傳遞一個位置。
<Prompt>
https://reacttraining.com/core/api/Prompt
<MemoryRouter>
將「URL」的歷史記錄保存在內存中(不讀取或寫入地址欄)的<路由器>。在測試和非瀏覽器環境(如React Native)中頗有用
`
import { MemoryRouter } from 'react-router' <MemoryRouter> <App/> </MemoryRouter>
`
- initialEntries: array
歷史堆棧中的一系列位置。這些多是具備{pathname,search,hash,state}或簡單字符串URL的完整的位置對象。
`
<MemoryRouter initialEntries={[ '/one', '/two', { pathname: '/three' } ]} initialIndex={1} > <App/> </MemoryRouter>
`
- initialIndex: number
initialEntries數組中的初始位置索引。
- getUserConfirmation: func
用於確認導航的功能。當使用<MemoryRouter>直接使用<Prompt>時,必須使用此選項。
- keyLength: number
location.key的長度。默認爲6
`
<MemoryRouter keyLength={12}/>
`
- children: node
要呈現的單個子元素。
<Redirect>
渲染<Redirect>將導航到新位置。新位置將覆蓋歷史堆棧中的當前位置,如服務器端重定向(HTTP 3xx)。
`
import { Route, Redirect } from 'react-router' <Route exact path="/" render={() => ( loggedIn ? ( <Redirect to="/dashboard"/> ) : ( <PublicHomePage/> ) )}/>
`
- to: string
要重定向到的網址。
`
<Redirect to="/somewhere/else"/>
`
- to: object
要重定向到的位置。
`
<Redirect to={{ pathname: '/login', search: '?utm=your+face', state: { referrer: currentLocation } }}/>
`
- push: bool
當爲true時,重定向會將新條目推入歷史記錄,而不是替換當前條目。
`
<Redirect push to="/somewhere/else"/>
`
- from: string
要重定向的路徑名。這隻能用於在<Switch>內部呈現<Redirect>時匹配位置。
有關詳細信息,請參閱<Switch children>。https://reacttraining.com/web/api/Switch/children-node
`
<Switch> <Redirect from='/old-path' to='/new-path'/> <Route path='/new-path' component={Place}/> </Switch>
`
<Route>
路由組件多是React Router中瞭解和學習使用的最重要的組件。其最基本的責任是在位置與路線的路徑匹配時呈現一些UI。
`
import { BrowserRouter as Router, Route } from 'react-router-dom' <Router> <div> <Route exact path="/" component={Home}/> <Route path="/news" component={NewsFeed}/> </div> </Router> <Home/> <!-- react-empty: 2 --> </div> <!-- react-empty: 1 --> <NewsFeed/> </div>
`
Route render methods
有3種方法可使用<Route>呈現某些東西:
** <Route component>
** <Route render>
** <Route children>
每一個在不一樣的狀況下都有用。您只能在給定的<Route>上使用這些方法之一。請看下面的解釋,瞭解爲何你有3個選項。大多數時候你會使用component。
Route props
全部三個渲染方法將經過相同的三個route props
** match
** location
** history
- component
僅當位置匹配時才呈現的React組件.它將與route props一塊兒呈現。
當您使用組件(而不是下面的渲染或子項)時,路由器使用React.createElement從給定組件建立一個新的React元素。
這意味着若是您向組件屬性提供內聯函數,則能夠在每一個渲染中建立一個新組件.這將致使現有組件卸載和新組件安裝,而不是僅更新現有組件
當使用內聯函數進行內聯渲染時,請使用render或child(下文)
`
<Route path="/user/:username" component={User}/> const User = ({ match }) => { return <h1>Hello {match.params.username}!</h1> }
`
- render: func
這容許方便的在線呈現和包裝,而不須要上述的不指望的從新安裝。您可使用組件支持爲您建立一個新的React元素,而沒必要在位置匹配時傳入要調用的函數。
渲染道具接收與組件渲染道具相同的全部route props。
警告:<Route component>取決於<Route render>,因此不要在同一個<Route>中使用二者
`
// 內聯呈現 <Route path="/home" render={() => <div>Home</div>}/> // 包裝/合成 const FadingRoute = ({ component: Component, ...rest }) => ( <Route {...rest} render={props => ( <FadeIn> <Component {...props}/> </FadeIn> )}/> ) <FadingRoute path="/cool" component={Something}/>
`
- children: func
有時您須要渲染路徑是否匹配該位置。在這些狀況下,可使用函數child prop。它的工做原理就像渲染,除了它被調用是否有匹配
children 渲染prop接收與組件和渲染方法相同的全部route props,除非路由未能匹配URL,則match爲null。
這容許您根據路線是否匹配來動態調整用戶界面。在這裏,若是路由匹配,咱們添加一個活動類
警告:<Route component>和<Route render>優先級高於<Route children>,因此不要在同一個<Route>中使用多個
`
<ul> <ListItemLink to="/somewhere"/> <ListItemLink to="/somewhere-else"/> </ul> const ListItemLink = ({ to, ...rest }) => ( <Route path={to} children={({ match }) => ( <li className={match ? 'active' : ''}> <Link to={to} {...rest}/> </li> )}/> ) //能夠用於動畫 <Route children={({ match, ...rest }) => ( {/* Animate will always render, so you can use lifecycles to animate its child in and out */} <Animate> {match && <Something {...rest}/>} </Animate> )}/>
`
- path: string
path-to-regexp理解的任何有效的URL路徑。
`
<Route path="/users/:id" component={User}/>
`
- exact: bool
當爲true時,僅當路徑與location.pathname徹底匹配時才匹配。
`
<Route exact path="/one" component={About}/>
`
______________________________________________
| path | location.pathname | exact | matches? |
| /one | /one/two | true | no |
| /one | /one/two | false | yes |
----------------------------------------------
- strict: bool
當爲true時,具備尾部斜槓的路徑將僅與具備尾部斜槓的location.pathname匹配。當在location.pathname中有其餘URL段時,這不起做用。
<Route strict path="/one/" component={About}/>
________________________________________
| path | location.pathname | matches? |
| /one/ | /one | no |
| /one/ | /one/ | yes |
| /one/ | /one/two | yes |
----------------------------------------
警告:strict能夠用來強制執行location.pathname沒有尾部斜槓,但爲了作到這一點,strict和exact必須是true。
`
<Route exact strict path="/one" component={About}/>
`
________________________________________
| path | location.pathname | matches? |
| /one | /one | yes |
| /one | /one/ | no |
| /one | /one/two | no |
----------------------------------------
- location: object
<Route>元素嘗試將其路徑與當前歷史記錄位置(一般是當前瀏覽器URL)進行匹配。可是,也能夠傳遞具備不一樣路徑名的位置進行匹配。
https://reacttraining.com/react-router/location.md
當您須要將<Route>匹配到當前歷史記錄位置之外的位置時,這是很是有用的,如「動畫轉換」示例所示。
https://reacttraining.com/react-router/web/example/animated-transitions
若是<Switch>元素包裹在<Switch>中並匹配傳遞給<Switch>(或當前歷史位置)的位置,則傳遞給<Route>的位置prop將被<開關>(在此給出)
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Switch.js#L51
<Router>
全部路由器組件的通用低級接口。一般,應用程序將使用其中一個高級路由器:
** <BrowserRouter>
** <HashRouter>
** <MemoryRouter>
** <NativeRouter>
** <StaticRouter>
使用低級「路由器」最多見的用例是將自定義歷史記錄與狀態管理庫(如Redux或Mobx)進行同步。請注意,這不是與React Router一塊兒使用狀態管理庫,而只用於深度集成。
`
import { Router } from 'react-router' import createBrowserHistory from 'history/createBrowserHistory' const history = createBrowserHistory() <Router history={history}> <App/> </Router>
`
- history: object
用於導航的歷史對象。
`
import createBrowserHistory from 'history/createBrowserHistory' const customHistory = createBrowserHistory() <Router history={customHistory}/>
`
- children: node
要呈現的單個子元素。
`
<Router> <App/> </Router>
`
<StaticRouter>
一個從不改變位置的<Router>。
當用戶實際上沒有點擊時,這在服務器端渲染場景中頗有用,所以該位置從未實際改變。所以,名稱:static。當您只需插入一個位置並在渲染輸出上做出斷言時,它也可用於簡單的測試。
如下是一個示例節點服務器,爲<Redirect>發送302狀態代碼,併爲其餘請求發送常規HTML
`
import { createServer } from 'http' import React from 'react' import ReactDOMServer from 'react-dom/server' import { StaticRouter } from 'react-router' createServer((req, res) => { // This context object contains the results of the render const context = {} const html = ReactDOMServer.renderToString( <StaticRouter location={req.url} context={context}> <App/> </StaticRouter> ) // context.url will contain the URL to redirect to if a <Redirect> was used if (context.url) { res.writeHead(302, { Location: context.url }) res.end() } else { res.write(html) res.end() } }).listen(3000)
`
- basename: string
全部位置的基本URL。正確格式化的基礎名稱應該有一個主要的斜槓,但沒有尾部斜線
`
<StaticRouter basename="/calendar"> <Link to="/today"/> // renders <a href="/calendar/today"> </StaticRouter>
`
- location: string
服務器接收到的URL,多是節點服務器上的req.url。
`
<StaticRouter location={req.url}> <App/> </StaticRouter>
`
- location: object
一個像{pathname,search,hash,state}的位置對象
`
<StaticRouter location={{ pathname: '/bubblegum' }}> <App/> </StaticRouter>
`
- context: object
一個簡單的JavaScript對象。在渲染過程當中,組件能夠向對象添加屬性以存儲有關渲染的信息。
`
const context = {}
<StaticRouter context={context}>
<App />
</StaticRouter>
`
當<Route>匹配時,它會將context對象傳遞給它做爲staticContext prop所呈現的組件。查看「服務器渲染」指南,
https://reacttraining.com/web/guides/server-rendering 瞭解有關如何自行執行此操做的更多信息。
渲染後,這些屬性可用於配置服務器的響應。
- children: node
<Switch>
渲染與位置匹配的第一個子元素<Route> 或 <Redirect> 。
<Switch>是獨特的,由於它僅僅渲染一個路由。相反,與位置匹配的每一個<Route>都會包含。
參考如下代碼:
`
<Route path="/about" component={About}/> <Route path="/:user" component={User}/> <Route component={NoMatch}/>
`
若是URL是/about,則<About>,<User>和<NoMatch>將所有渲染,由於它們都與路徑匹配。這是經過設計,容許咱們以許多方式將<Route>組合到咱們的應用程序中,如側邊欄和麪包屑,引導標籤等。
然而,偶爾,咱們只想選擇一個<路線>來渲染。若是咱們在/關於咱們不想也匹配/:用戶(或顯示咱們的「404」頁面)。如下是使用Switch的方法:
`
import { Switch, Route } from 'react-router' <Switch> <Route exact path="/" component={Home}/> <Route path="/about" component={About}/> <Route path="/:user" component={User}/> <Route component={NoMatch}/> </Switch>
`
如今,若是咱們在/ about,<Switch>將開始尋找匹配的<Route>。 <Route path =「/ about」/>將匹配,<Switch>將中止尋找匹配並呈現<About>。一樣,若是咱們在/ michael,那麼<User>將呈現。
這對於動畫轉換也是有用的,由於匹配的<Route>呈現與前一個相同的位置。
`
<Fade> <Switch> {/* there will only ever be one child here */} <Route/> <Route/> </Switch> </Fade> <Fade> <Route/> <Route/> {/* there will always be two children here, one might render null though, making transitions a bit more cumbersome to work out */} </Fade>
`
Switch props
- location: object
要用於匹配子元素而不是當前歷史位置(一般是當前瀏覽器URL)的位置對象。
- children: node
<Switch>的全部子項應爲<Route>或<Redirect>元素。只有匹配當前位置的第一個子元素纔會呈現
<Route>元素使用它們的路徑匹配匹配,而且<Redirect>元素使用它們與prop相匹配。沒有路徑的<Route>或路由不正確的<Redirect>將始終與當前位置匹配。
當您在<Switch>中包含<Redirect>時,它可使用任何<Route>的位置匹配道具:path,exact和strict。只是path prop的別名。
若是給定位置支持<Switch>,它將覆蓋匹配的子元素上的path prop。
`
<Switch> <Route exact path="/" component={Home}/> <Route path="/users" component={Users}/> <Redirect from="/accounts" to="/users"/> <Route component={NoMatch}/> </Switch>
`
history
本文檔中的「歷史」和「歷史對象」一詞是指歷史包,https://github.com/ReactTraining/history 這是React
Router的惟一兩個主要依賴之一(除了React自己)以外,而且其提供用於在各類環境中的JavaScript中管理會話歷史的幾種不一樣實現
使用如下術語:
「browser history」 : DOM特定的實現,可用於支持HTML5歷史記錄API的Web瀏覽器
「hash history」 : 遺留網絡瀏覽器的DOM特定實現
「memory history」 : 內存中的歷史記錄實現,可用於測試和非DOM環境(如React Native)
history對象一般具備如下屬性和方法:
length : (number)歷史堆棧中的條目數
action : (string)當前動做(PUSH,REPLACE或POP)
location : (object) 當前位置。具備如下屬性:
pathname: URL的路徑
search: URL查詢字符串
hash: URL哈希片斷
state: 位置特定的狀態被提供給例如。當這個位置被推到堆棧上時,push(路徑,狀態)。僅在瀏覽器和內存歷史記錄中可用。
push : (path, [state]) - (function) 將新條目推入歷史堆棧
replace : (path, [state]) - (function) 替換歷史堆棧上的當前條目
go(n) : (function) 將歷史堆棧中的指針移動n個條目
goBack() : (function) 至關於 go(-1)
goForward() : (function) 至關於 go(1)
block : (function) 防止導航 (https://github.com/ReactTraining/history#blocking-transitions)
history is mutable
history 對象是可變的。所以,建議從<Route>的渲染道具訪問位置,而不是從history.location訪問。這樣能夠確保您對於React的假設在生命週期掛鉤中是正確的。例如:
`
class Comp extends React.Component { componentWillReceiveProps(nextProps) { // will be true const locationChanged = nextProps.location !== this.props.location // INCORRECT, will *always* be false because history is mutable. const locationChanged = nextProps.history.location !== this.props.history.location } } <Route component={Comp}/>
`
詳細信息參考:https://github.com/ReactTraining/history#properties
location
位置表明了應用程序如今的位置,您想要哪裏,甚至是哪裏。看起來像這樣
`
{ key: 'ac3df4', // not with HashHistory! pathname: '/somewhere' search: '?some=search-string', hash: '#howdy', state: { [userDefined]: true } }
`
路由器將在幾個地方爲您提供位置對象
Route component as this.props.location
Route render as ({ location }) => ()
Route children as ({ location }) => ()
withRouter as this.props.location
它也發如今history.location,但你不該該使用它,由於它的可變。您能夠在歷史文檔中閱讀更多信息。
https://reacttraining.com/web/api/history
位置對象從不被突變,所以您能夠在生命週期鉤子中使用它來肯定什麼時候導航,這對數據獲取和動畫很是有用。
`
componentWillReceiveProps(nextProps) { if (nextProps.location !== this.props.location) { // navigated! } }
`
您能夠提供位置而不是字符串到導航的各個地方:
Web Link to
Native Link to
Redirect to
history.push
history.replace
一般您只需使用一個字符串,但若是您須要添加一些「位置狀態」,只要應用程序返回到該特定位置,就可使用位置對象。若是您想基於導航歷史而不只僅是路徑(如模態)分支UI,這頗有用。
`
// 最經常使用的
<Link to="/somewhere"/> // but you can use a location instead const location = { pathname: '/somewhere' state: { fromDashboard: true } } <Link to={location}/> <Redirect to={location}/> history.push(location) history.replace(location)
`
最後,您能夠將location傳遞給如下組件:
Route (https://reacttraining.com/web/api/Route/location)
Switch (https://reacttraining.com/web/api/Route/location)
match
匹配對象包含有關<Route path>如何匹配URL的信息。匹配對象包含如下屬性:
params - (object)從對應於路徑的動態段的URL解析的鍵/值對
isExact - (boolean)true若是整個URL匹配(沒有尾隨字符
path - (string)用於匹配的路徑模式。做用於構建嵌套的<Route>
url - (string)URL的匹配部分。做用於構建嵌套的<Link> s
能夠在如下地方訪問匹配對象:
Route component as this.props.match
Route render as ({ match }) => ()
Route children as ({ match }) => ()
withRouter as this.props.match
matchPath as the return value
若是路由沒有路徑,所以始終匹配,您將得到最接近的父級匹配。與Router同樣。
matchPath
這容許您使用除了正常渲染循環以外的<Route>使用相同的匹配代碼,例如在服務器上渲染以前收集數據依賴關係。
`
import { matchPath } from 'react-router' const match = matchPath('/users/123', { path: '/users/:id', exact: true, strict: false })
`
- pathname
第一個參數是要匹配的路徑名。若是在Node.js的服務器上使用這個,那麼它將是req.url。
- props
第二個參數是匹配的道具,它們與匹配props相同route接受:
`
{ path, // like /users/:id strict, // optional, defaults to false exact // optional, defaults to false }
`
withRouter
您能夠經過withRouter高階組件訪問歷史對象的屬性和最接近的<Route>的匹配。隨着路由每次路由改變時,路由器會從新渲染其組件,路徑與<路徑>渲染道具:{match,location,history}相同。
`
import React from 'react' import PropTypes from 'prop-types' import { withRouter } from 'react-router' // A simple component that shows the pathname of the current location class ShowTheLocation extends React.Component { static propTypes = { match: PropTypes.object.isRequired, location: PropTypes.object.isRequired, history: PropTypes.object.isRequired } render() { const { match, location, history } = this.props return ( <div>You are now at {location.pathname}</div> ) } } // Create a new component that is "connected" (to borrow redux // terminology) to the router. const ShowTheLocationWithRouter = withRouter(ShowTheLocation)
`
重要的提示
若是您使用withRouter來阻止更新被shouldComponentUpdate阻止,那麼重要的是使用Router打包實現shouldComponentUpdate的組件。例如,使用Redux時
`
// This gets around shouldComponentUpdate withRouter(connect(...)(MyComponent)) // This does not connect(...)(withRouter(MyComponent))
`
有關詳細信息,請參閱本指南。 https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md
靜態方法和屬性
包裝組件的全部非反應特定靜態方法和屬性將自動複製到「已鏈接」組件。
Component.WrappedComponent
被包裝的組件在返回的組件上做爲靜態屬性WrappedComponent公開,能夠用於單獨測試組件。
`
// MyComponent.js export default withRouter(MyComponent) // MyComponent.test.js import MyComponent from './MyComponent' render(<MyComponent.WrappedComponent location={{...}} ... />)
`
wrappedComponentRef: func
將做爲參考傳遞給包裝組件的函數。
`
class Container extends React.Component { componentDidMount() { this.component.doSomething() } render() { return ( <MyComponent wrappedComponentRef={c => this.component = c}/> ) } }
`