Create by jsliang on 2019-04-26 13:13:18
Recently revised in 2019-04-29 15:25:01php
Hello 小夥伴們,若是以爲本文還不錯,記得給個 star , 小夥伴們的 star 是我持續更新的動力!GitHub 地址html
【2019-08-16】Hello 小夥伴們,因爲 jsliang 對文檔庫進行了重構,這篇文章中的一些連接可能失效,而 jsliang 缺少精力維護掘金這邊的舊文章,對此深感抱歉。請須要獲取最新文章的小夥伴,點擊上面的 GitHub 地址,去文檔庫查看調整後的文章。前端
不折騰的前端,和鹹魚有什麼區別react
返回目錄git
前端路由,是指改變 URL 路徑的形式,從而切換到不一樣的頁面,例如:github
localhost:3000/home
localhost:3000/user
經過切換不一樣的 URL,顯示不一樣的頁面,從而有了 路由 的概念。web
這篇文章咱們講解在 React 中如何經過 React Router 這個插件,靈活使用路由。ajax
jsliang 瞎吹的,最好本身百度 前端路由 是啥。npm
網上有不少 React Router 文章了,例如:redux
爲什麼 jsliang 要屢次一舉?
當前版本:"react-router-dom": "^5.0.0"
首先,在 Create React App 中,咱們引用 React Router:
npm i react-router-dom -S
而後,在 src 目錄下新建 pages 用來存放頁面,並修改 App.js:
案例:App.js
import React, { Fragment } from 'react';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import ScrollToTop from './components/ScrollToTop';
import Header from './components/Header';
import TimeLine from './pages/TimeLine';
import NotFound from './pages/404';
function App() {
return (
<Fragment> <BrowserRouter> <Header /> <ScrollToTop> <Switch> <Redirect from="/" to="/timeline" exact /> <Route path="/timeline" component={TimeLine}></Route> <Route component={NotFound}></Route> </Switch> </ScrollToTop> </BrowserRouter> </Fragment> ); } export default App; 複製代碼
最後,經過在 App.js 中如此定義,便可定義對應的組件,並渲染對應頁面和進行跳轉。
下面咱們拿一些經常使用的進行介紹:
import {
BrowserRouter,
HashRouter,
Redirect,
Route,
NavLink,
Link,
MemoryRouter,
Switch,
withRouter
} from "react-router-dom";
複製代碼
<BrowserRouter>
:路由組件包裹層。<Route>
和 <Link>
的包裹層。<HashRouter>
:路由組件包裹層。相對於 <BrowserRouter>
來講,更適合靜態文件的服務器。<Redirect>
:路由重定向。渲染 <Redirect>
將使導航到一個新的地址。<Route>
:路由。定義一個路由頁面,用來匹配對應的組件(Component)和路由路徑。<NavLink>
:活躍連接。當 URL 中的路徑等於該路由定義的路徑時,該標籤能夠呈現它定義的 activeClassName
。<Link>
:連接。用來跳轉到 <Route>
對應的路由(Component) 中。<MemoryRouter>
:暫未使用。<Router>
能在內存中保存 URL
的歷史記錄。很適合在測試環境和非瀏覽器環境中使用,例如 React Native。<Switch>
:路由分組。渲染與該地址匹配的第一個子節點 <Route>
或者 <Redirect>
。能夠利用 <Switch>
作分組。<withRouter>
:路由組合。經過 <withRouter>
高階組件訪問 history
對象的屬性和最近的 <Route>
的 match
。或者利用它來結合 Redux。<BrowserRouter>
會爲你建立一個專門的 history 對象,用來記錄你的路由,從而可以返回上一頁或者跳轉到指定的路由頁面。
區別於
<HashRouter>
,有響應請求的服務器時使用<BrowserRouter>
,使用的是靜態文件的服務器,則用<HashRouter>
。
簡單案例:
<BrowserRouter>
<Header /> <Route path="/" exact component={TimeLine}></Route> <Route path="/timeline" component={TimeLine}></Route> </BrowserRouter>
複製代碼
import { BrowserRouter } from 'react-router-dom'
<BrowserRouter
basename={optionalString}
forceRefresh={optionalBool}
getUserConfirmation={optionalFunc}
keyLength={optionalNumber}
>
<App/>
</BrowserRouter>
複製代碼
basename: string
爲裏面的子目錄提供基礎路徑名,例如:
<BrowserRouter basename="/calendar">
<Link to="/today"/> {/* 渲染爲 <a href="/calendar/today"> */} </BrowserRouter> 複製代碼
getUserConfirmation: function
用於確認導航的功能。
// 默認使用 window.confirm。
const getConfirmation = (message, callback) => {
const allowTransition = window.confirm(message)
callback(allowTransition)
}
<BrowserRouter getUserConfirmation={getConfirmation}/>
複製代碼
forceRefresh: bool
若是爲 true,則路由器將在頁面導航中使用整頁刷新
const supportsHistory = 'pushState' in window.history
<BrowserRouter forceRefresh={!supportsHistory}/>
複製代碼
keyLength: number
設置它裏面路由的 location.key
的長度。默認爲 6。
key 的做用:點擊同一個連接時,每次該路由下的 location.key都會改變,能夠經過 key 的變化來刷新頁面。
<BrowserRouter keyLength={12}/>
複製代碼
使用 URL
的 hash
部分(即 window.location.hash
)的 <Router>
使 UI
與 URL
保持同步。
重要提示:Hash
歷史記錄不支持 location.key
或 location.state
。
import { HashRouter } from 'react-router-dom'
<HashRouter>
<App/>
</HashRouter>
複製代碼
basename: string
全部位置的基本 URL
,格式正確的基本名應該有一個前導斜線,但結尾不能有斜線。
<HashRouter basename="/calendar"/>
<Link to="/today"/>
{/* 渲染爲 <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
- 建立 #/
和的 #/sunshine/lollipops
noslash
- 建立 #
和的 #sunshine/lollipops
hashbang
- 建立 ajax crawlable
,如 #!/
和 #!/sunshine/lollipops
默認爲 slash
。
在應用程序周圍提供聲明式的,可訪問的導航。
to: string
連接位置的字符串表示,經過鏈接位置的路徑名,搜索和 hash
屬性建立。
<Link to='/courses?sort=name'>字符串形式跳轉</Link>
複製代碼
to: object
一個能夠具備如下任何屬性的對象:
pathname
: 表示要連接到的路徑的字符串。search
: 表示查詢參數的字符串形式。hash
: 放入網址的 hash
,例如 #a-hash
。state
: 狀態持續到 location
。<Link to={{
pathname: '/courses', // 基礎路徑
search: '?sort=name', // 匹配字段
hash: '#the-hash', // 對應內鏈
state: { fromDashboard: true } // 未知
}}>
對象形式跳轉
</Link>
複製代碼
replace: bool
若是爲 true
,則單擊連接將替換歷史堆棧中的當前入口,而不是添加新入口。
<Link to="/courses" replace>替換當前 hash 路徑</Link>
複製代碼
還能夠傳遞想要放在 <a>
上的屬性,例如標題,ID
、className
等。
<Link to="/test" id="myTest">測試 1</Link>
複製代碼
一個特殊版本的 Link,當它與當前 URL 匹配時,爲其渲染元素添加樣式屬性。
<NavLink to="/timeline" activeClassName="active">首頁</NavLink>
activeClassName: string
要給出的元素的類處於活動狀態時。默認的給定類是 active
。它將與 className
屬性一塊兒使用。
<NavLink
to="/faq"
activeClassName="selected"
>FAQs</NavLink>
複製代碼
activeStyle: object
當元素處於 active 時應用於元素的樣式。
<NavLink
to="/faq"
activeStyle={{
fontWeight: 'bold',
color: 'red'
}}
>FAQs</NavLink>
複製代碼
exact: bool
若是爲 true
,則僅在位置徹底匹配時才應用 active
的類/樣式。
<NavLink
exact
to="/profile"
>Profile</NavLink>
複製代碼
isActive: function
一個爲了肯定連接是否處於活動狀態而添加額外邏輯的函數,若是你想作的不只僅是驗證連接的路徑名與當前 URL 的 pathname 是否匹配,那麼應該使用它
// 若是連接不只僅匹配 events/123,而是全部奇數連接都匹配
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>
複製代碼
<Router>
能在內存中保存 URL
的歷史記錄(並不會對地址欄進行讀寫)。很適合在測試環境和非瀏覽器環境中使用,例如 React Native。
<MemoryRouter>
<App/>
</MemoryRouter>
複製代碼
initialEntries: array
history
棧中的一個 location
數組。這些多是具備 { pathname, search, hash, state }
或簡單的 URL
字符串的完整地址對象。
<MemoryRouter
initialEntries={[ '/one', '/two', { pathname: '/three' } ]}
initialIndex={1}
>
<App/>
</MemoryRouter>
複製代碼
initialIndex: number
在 initialEntries
數組中的初始化地址索引。
getUserConfirmation: function
用於確認導航的函數。在使用 <MemoryRouter>
時,直接使用 <Prompt>
,你必須使用這個選項。
keyLength: number
location.key
的長度。默認爲 6。
渲染 <Redirect>
將使導航到一個新的地址。這個新的地址會覆蓋 history
棧中的當前地址,相似服務器端(HTTP 3xx)的重定向。
咱們能夠設置某個路由重定向到另外一個路由,例以下面即對 /
徹底匹配重定向到 /timeline
頁面。
<Redirect from="/" to="/timeline" exact />
複製代碼
from: string
重定向 from
的路徑名。能夠是任何 path-to-regexp
可以識別的有效的 URL
路徑。
全部匹配的 URL
參數都提供給 to
中的模式。
必須包含在 to
中使用的全部參數。
to
未使用的其餘參數將被忽略。
<Switch>
<Redirect from="/old-path" to="/new-path" /> <Route path="/new-path" component={Place} /> </Switch> 複製代碼
to: string
重定向到的 URL
,能夠是任何 path-to-regexp
可以理解有效 URL
路徑。
在 to
中使用的 URL
參數必須由 from
覆蓋。
<Redirect to="/somewhere/else" />
複製代碼
to: object
重定向到的 location
,pathname
能夠是任何 path-to-regexp
可以理解的有效的 URL
路徑。
<Redirect
to={{
pathname: "/login",
search: "?utm=your+face",
state: { referrer: currentLocation }
}}
/>
複製代碼
push: bool
當 true
時,重定向會將新地址推入 history
中,而不是替換當前地址。
<Redirect push to="/somewhere/else" />
複製代碼
exact: bool
徹底匹配 from
。
只要應用程序位置與 Route 的路徑匹配,組件就會被渲染。
只有當位置匹配時纔會渲染的 React 組件。
<Route path="/user/:username" component={User}/>
const User = ({ match }) => {
return <h1>Hello {match.params.username}!</h1>
}
複製代碼
render: function
這容許方便的內聯渲染和包裹,而不是上面那種不想要的從新安裝的解釋
能夠傳遞一個在位置匹配時調用的函數,而不是使用屬性爲您建立新的 React element component
,該 render
屬性接收全部相同的 route props
的 component
渲染屬性。
// 行內編寫
<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: function
有時你須要渲染路徑是否匹配位置。在這些狀況下,您可使用函數 children
屬性,它的工做原理與渲染徹底同樣,不一樣之處在於它是否存在匹配。
children
渲染道具接收全部相同的 route props
做爲 component
和 render
方法,若是 Route
與 URL
不匹配,match
則爲 null
,這容許你動態調整你的 UI
界面,基於路線是否匹配,若是路線匹配咱們則添加一個 active
類。
<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>
)}/>
)
複製代碼
path: string
任何 path-to-regexp
能夠解析的有效的 URL
路徑
<Route path="/users/:id" component={User}/>
複製代碼
exact: bool
若是爲 true
,則只有在路徑徹底匹配 location.pathname
時才匹配。
path | location.pathname | exact | matches? |
---|---|---|---|
/one | /one/two | true | no |
/one | /one/two | false | yes |
<Route exact path="/one" component={About}/>
複製代碼
jsliang 我的經驗:
exact
屬性後,會徹底匹配路徑;若是沒有加,則二級路徑也會匹配當前路徑(例如 /timeline/book
)。<BrowserRouter>
<Route path="/" exact component={TimeLine}></Route>
<Route path="/timeline" component={TimeLine}></Route>
</BrowserRouter>
複製代碼
extra
的值,從而判斷是否須要加載某個組件。const Home = () => <div>Home</div>;
const App = () => {
const someVariable = true;
return (
<Switch>
{/* these are good */}
<Route exact path="/" component={Home} />
<Route
path="/about"
render={props => <About {...props} extra={someVariable} />}
/>
{/* do not do this */}
<Route
path="/contact"
component={props => <Contact {...props} extra={someVariable} />}
/>
</Switch>
);
};
複製代碼
location: object
一個 <Route>
元素嘗試其匹配 path
到當前的歷史位置(一般是當前瀏覽器 URL)。可是,也能夠經過location 一個不一樣 pathname
的匹配。
sensitive: bool
若是路徑區分大小寫,則爲 true
,則匹配。
path | location.pathname | sensitive | matches? |
---|---|---|---|
/one | /one | true | yes |
/One | /one | true | no |
/One | /one | false | yes |
<Route sensitive path="/one" component={About}/>
複製代碼
渲染與該地址匹配的第一個子節點 <Route>
或者 <Redirect>
。
能夠利用 <Switch>
作分組,即當有匹配時,匹配對應 path
對應的組件;若是沒有匹配,則匹配 NotFound
頁面。
<BrowserRouter>
<Header /> <Switch> <Route path="/" exact component={TimeLine}></Route> <Route path="/timeline" component={TimeLine}></Route> <Route component={NotFound}></Route> </Switch> </BrowserRouter>
複製代碼
history
是一個包,在你安裝 React Router 的時候,會做爲它依賴包安裝到項目中,因此你能夠直接使用 history
中的屬性和方法:
length
- (number
類型) history
堆棧的條目數action
- (string
類型) 當前的操做(push
, replace
, pop
)location
- (object
類型) 當前的位置。location
會具備如下屬性:
pathname
- (string
類型) URL 路徑search
- (string
類型) URL 中的查詢字符串hash
- (string
類型) URL 的哈希片斷state
- (object
類型) 提供給例如使用 push(path, state)
操做將location
放入堆棧時的特定 location
狀態。只在瀏覽器和內存歷史中可用push(path, [state])
- (function
類型) 在 history
堆棧添加一個新條目replace(path, [state])
- (function
類型) 替換在 history
堆棧中的當前條目go(n)
- (function
類型) 將 history
堆棧中的指針調整 n
goBack()
- (function
類型) 等同於 go(-1)
goForward()
- (function
類型) 等同於 go(1)
block(prompt)
- (function
類型) 阻止跳轉隨着應用的增加,代碼包會隨着生長。
到最後你會發現,你打包後的 js 文件大地太多離譜。
因此,咱們須要經過代碼分割,依據不一樣的路由,加載不一樣的 js 文件。
npm i react-loadable -S
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Loadable from 'react-loadable';
const Loading = () => <div>Loading...</div>;
const Home = Loadable({
loader: () => import('./routes/Home'),
loading: Loading,
});
const About = Loadable({
loader: () => import('./routes/About'),
loading: Loading,
});
const App = () => (
<Router>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
</Switch>
</Router>
);
複製代碼
npm run build
src/components/ScrollToTop/index.js
import { Component } from 'react';
import { withRouter } from 'react-router-dom';
class ScrollToTop extends Component {
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
window.scrollTo(0, 0)
}
}
render() {
return this.props.children
}
}
export default withRouter(ScrollToTop);
複製代碼
src/App.js
import React, { Fragment } from 'react';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import ScrollToTop from './components/ScrollToTop';
import Header from './components/Header';
import TimeLine from './pages/TimeLine';
import NotFound from './pages/404';
function App() {
return (
<Fragment> <BrowserRouter> <Header /> <ScrollToTop> <Switch> <Redirect from="/" to="/timeline" exact /> <Route path="/timeline" component={TimeLine}></Route> <Route component={NotFound}></Route> </Switch> </ScrollToTop> </BrowserRouter> </Fragment> ); } export default App; 複製代碼
暫未實現
在項目中,咱們更但願 React Router 和 React Redux 合併起來,這時候能夠:
// before
export default connect(mapStateToProps)(Something)
// after
import { withRouter } from 'react-router-dom'
export default withRouter(connect(mapStateToProps)(Something))
複製代碼
若是你純粹過文檔(官方文檔,jsliang 的文檔),你會以爲毫無趣味、了無生趣、乏味、沉悶……
因此,jsliang 的學法是:開啓了一個項目,邊翻閱文檔,邊應用到項目中,並進行 Mark 標記,以便下次使用。
如此,該文檔雖然完結了,可是仍未完結!完結的是我過完了官方文檔,未完結的是 React Router 在我項目中可能有其餘應用,須要我一一添加進來。
jsliang 廣告推送:
也許小夥伴想了解下雲服務器
或者小夥伴想買一臺雲服務器
或者小夥伴須要續費雲服務器
歡迎點擊 雲服務器推廣 查看!
jsliang 的文檔庫 由 梁峻榮 採用 知識共享 署名-非商業性使用-相同方式共享 4.0 國際 許可協議進行許可。
基於github.com/LiangJunron…上的做品創做。
本許可協議受權以外的使用權限能夠從 creativecommons.org/licenses/by… 處得到。