React Router 現在已經是 React 開發單頁應用必備技能,自升級 V4 版本以來,許多核心 API 都進行了重寫,践行路由即組件的概念,本文是我學習 React Router V4 以來的一些總結。
介紹#
React-Router V4 是 react-router 的一次重大更新,許多核心 API 都已改變,使用 react-router4 不需要對路由進行集中式配置,react-router 4 的核心是一切皆組件。
react-router 4 一共被拆分為三個包:react-router、react-router-dom、react-router-native,react-router 提供了 React Router 的核心路由功能,包括 Router, Route, Switch 等,但是我們不會直接使用它。react-router-dom 和 react-router-native 提供在特定運行環境下的路由組件。如果你需要開發在瀏覽器中運行的 Web 應用,則應該安裝 react-router-dom。同樣,如果你需要開發 React Native 應用程序,則應該安裝 react-router-native。這兩者都將安裝 react-router 作為依賴項。
react-router-dom#
react-router 使用 react-router-dom 作為瀏覽器端的路由,提供了 BrowserRouter,Route,Link 等 api, 通過 DOM 的事件控制路由。在 Web 開發過程中,我們更多是使用 react-router-dom。本文的討論也僅限於 react-router-dom。
安裝
npm install react-router-dom --save
使用#
Router#
react-router4 的使用首先需要選擇 Router,Router 用於包裹在應用最外層。Router 有兩種類型:HashRouter 和 BrowserRouter,其表現方式也有所不同,使用時需要區分。
HashRouter 與 BrowserRouter#
從表面區分 HashRouter 和 BrowserRouter 的方法就是 HashRouter 的 url 中有個 #,例如 localhost:3000/#,HashRouter 通過 hash 值來對路由進行控制。如果你使用 HashRouter,你的路由就會默認有這個 #。
BrowserRouter 的 url 中沒有 #,它的 url 如http://localhost:3001/user/login,BrowserRouter 的原理是依賴 HTML5 的 history API 實現的路由機制。
HashRouter 和 BrowserRouter 都具有 basename 屬性,如果你的 URL 不是位於網站根目錄,而是放在子目錄裡,你需要設置這個屬性。如下:
<BrowserRouter basename="/calendar"/>
<Link to="/today"/> // 渲染為 <a href="/calendar/today">
Route#
Route 是 Router 的子元素,控制路徑對應顯示的組件。常用屬性有 exact、path 以及 component。
考慮以下代碼:
<Route path="/" exact component={HomePage} />
<Route path="/users" component={UsersPage} />
react-router4 的路由是包含性的,多個 Route 可以同時進行匹配和渲染,exact 控制到路徑匹配成功時不會再繼續向下匹配,在面代碼中,我們試圖根據路徑渲染 HomePage 或者 UsersPage。如果從 Route 刪除了 exact 屬性,那麼在瀏覽器中訪問 /users 時,HomePage 和 UsersPage 組件將同時被渲染。
Switch#
在 Router 組件中的任意位置創建多個,但通常我們會把它們放在同一個位置。使用組件來包裹一組。會遍歷自身的子元素(即路由)並對第一個匹配當前路徑的元素進行渲染。考慮如下代碼:
<Switch>
<Route exact path="/" component={DashBoard} />
<Route path="/user" component={User} />
</Switch>
如果去掉 Switch 組件,當我們訪問 /user 的時候,路由會同時匹配 “/” 和 /user,將同時渲染 DashBoard 和 User 組件。
Link vs NavLink#
react-router4 提供了兩種導航 API,用於頁面切換,當頁面切換時,頁面不會重新加載,但是組件會被重新渲染。它們作用相同,但 NavLink 在匹配 URL 成功時,可以提供一些額外的樣式能力。
Link
Link 提供 to 屬性控制跳轉地址,可傳入字符串或者對象。如下:
<Link to="/courses"/>to: object
<Link to={{
pathname: '/courses',
search: '?sort=name',
hash: '#the-hash',
state: { fromDashboard: true }
}}/>
NavLink
NavLink 可以給當前匹配成功的鏈接提供一個 className 類名,常在 Tab 導航中使用。
<nav>
<NavLinkto="/app"exact activeClassName="active">Home</NavLink>
<NavLinkto="/app/users"activeClassName="active">Users</NavLink>
<NavLinkto="/app/products"activeClassName="active">Products</NavLink>
</nav>
路徑參數#
在 react router4 中,match 用於獲取路徑上的參數,match 是使用渲染時傳遞到組件內的一個 props,在 react 組件內部通過 this.props.match 獲取 match 的屬性,
考慮如下代碼:
<Switch>
<Route exact path="/" component={DashBoard} />
<Route path="/user/:id" component={User} />
<Route path="/user" component={User} />
</Switch>
當訪問http://localhost:3001/user/123 時,打印 this.props.match 的內容。
match 獲取的屬性主要有:
然後,通過 this.props.match.params.id 就可以獲取路由匹配的 id 了。
withRouter#
試想,如果組件沒有通過渲染,該如何獲取 history、match、location 等 props 呢?react router4 提供了一個高階組件 withRouter。使用方法如下:
import { withRouter } from 'react-router-dom';
使用 withRouter 有兩種辦法,第一種簡潔的方法是使用裝飾器,如下:
@withRouter
class AuthRoute extends React.Component {
}
另一種方法直接調用 withRouter 包裹原來的組件返回一個新的組件:
class Auth extends React.Component {
}
const AuthRoute = withRouter(Auth)
通過以上兩種方法,就能在組件內部使用路由的 props 了。如下:
const { match,location,history} = this.props;
結語#
關於 react router4, 本文只是講解了一些常用的 api 和用法,需要學習的還有很多,這裡只是開始。