原文:
All About React Router 4 筆記
此文來自一篇英文博客,記錄學習時總結的一些知識點嫁怀,如有錯誤针余,請指正云矫,謝謝!
React Router 4
帶來新的API以及新的心智模型窒盐。
Inclusive Routing 引入路由
const PrimaryLayout = () => (
<div className="primary-layout">
<header>
Our React Router 4 App
<Route path="/users" component={UsersMenu} />
</header>
<main>
<Route path="/" exact component={HomePage} />
<Route path="/users" component={UsersPage} />
</main>
</div>
)
UsersMenu
和 UsersPage
可以通過同一個路由被渲染到當前頁面中啃奴,
exact
精確匹配路由 '/'
Switch 路由組
當你需要將路由匹配到一個路由組時潭陪,使用 Switch
可以匹配到唯一路由
const PrimaryLayout = () => (
<div className="primary-layout">
<PrimaryHeader />
<main>
<Switch>
<Route path="/" exact component={HomePage} />
<Route path="/users/add" component={UserAddPage} />
<Route path="/users" component={UsersPage} />
<Redirect to="/" />
</Switch>
</main>
</div>
)
當使用 Switch
時,只有一個路由會被渲染。
我們仍然需要使用 exact
當設 HomePage
為首選被渲染的組件依溯。否則等瀏覽到 /users
或則會使 '/users/add' 時老厌,HomePage
組件仍然會被渲染,如果發(fā)生同時渲染黎炉,那么先渲染的組件排在最前面梅桩。
當路由匹配 /users/add
時,也會同時匹配到 /users
路由拜隧,為確保優(yōu)先渲染UserAddPage
可以將這個組件寫到 UsersPage
前面,如果相反趁仙,則調換順序洪添。
當然也可以將所有路由設置為 exact
精確匹配,這樣就不存在先后問題雀费。
Redirect 重定向
當 Switch
沒有匹配到任意一個路由的時候干奢,將會發(fā)生路由重定向。
"Index Routes" and "Not Found" (已移除)
在 V4 中不在使用 <IndexRoute>
, 而是使用 <Route exact>
精確匹配路由盏袄。
如果沒有路由被匹配忿峻,可以使用 <Switch>
和 <Redirect>
去重定向到默認路由,或者重定向到 404頁面
Nested Layouts 嵌套布局
這里展示兩種不同的寫法辕羽,以及為什么第二種是更好的寫法
第一種采用 exact
精確匹配路由
const PrimaryLayout = props => {
return (
<div className="primary-layout">
<PrimaryHeader />
<main>
<Switch>
<Route path="/" exact component={HomePage} />
<Route path="/users" exact component={BrowseUsersPage} />
<Route path="/users/:userId" component={UserProfilePage} />
<Route path="/products" exact component={BrowseProductsPage} />
<Route path="/products/:productId" component={ProductProfilePage} />
<Redirect to="/" />
</Switch>
</main>
</div>
)
}
這種寫法在技術上是可行的逛尚,但是問題在于,props.match
是通過 <Route>
組件傳遞的刁愿。組件 BrowseUsersPage
的子組件并不是通過 <Route>
嵌套路路由中绰寞,子組件是不能直接拿到 props.match
的。
當然這里可以通過高階組件的方式將子組件包裝:withRouter()
第二種寫法在第一種寫法的基礎上做了修改铣口,通過路由嵌套的方式布局組件滤钱,并且不再需要使用 exact
精確匹配路由,也不必使用 withRouter() 加工組件脑题。
const PrimaryLayout = () => (
<div className="primary-layout">
<PrimaryHeader />
<main>
<Switch>
<Route path="/" exact component={HomePage} />
<Route path="/users" component={UserSubLayout} />
<Route path="/products" component={ProductSubLayout} />
<Redirect to="/" />
</Switch>
</main>
</div>
);
const UserSubLayout = () => (
<div className="user-sub-layout">
<aside>
<UserNav />
</aside>
<div className="primary-content">
<Switch>
<Route path="/users" exact component={BrowseUsersPage} />
<Route path="/users/:userId" component={UserProfilePage} />
</Switch>
</div>
</div>
);
const UserSubLayout = props => (
<div className="user-sub-layout">
<aside>
<UserNav />
</aside>
<div className="primary-content">
<Switch>
<Route
path={props.match.path}
exact
component={BrowseUsersPage}
/>
<Route
path={`${props.match.path}/:userId`}
component={UserProfilePage}
/>
</Switch>
</div>
</div>
);
Match 匹配對象
Match
對象提供了一下幾種屬性
- params - (object) Key/value pairs parsed from the URL corresponding to the dynamic segments of the path
- isExact - (boolean) true if the entire URL was matched (no trailing characters)
- path - (string) The path pattern used to match. Useful for building nested <Route>s
- url - (string) The matched portion of the URL. Useful for building nested <Link>s
match.path vs match.url
當路由不攜帶參數(shù)是兩者的輸出是相同的字符串件缸,嘗試打印這兩者。
當路由匹配到例如 /users/5
時叔遂,match.ur
l 將會輸出 "/users/5" ; 而 match.path
輸出 "/users/:userId".
Avoiding Match Collisions 避免匹配沖突
const UserSubLayout = ({ match }) => (
<div className="user-sub-layout">
<aside>
<UserNav />
</aside>
<div className="primary-content">
<Switch>
<Route exact path={props.match.path} component={BrowseUsersPage} />
<Route path={`${match.path}/add`} component={AddUserPage} />
<Route path={`${match.path}/:userId/edit`} component={EditUserPage} />
<Route path={`${match.path}/:userId`} component={UserProfilePage} />
</Switch>
</div>
</div>
)
path-to-regexp 用于校驗路由參數(shù)
var re = pathToRegexp('/:foo(\\d+)')
// keys = [{ name: 'foo', ... }]
re.exec('/123')
//=> ['/123', '123']
re.exec('/abc')
//=> null
Authorized Route 路由認證他炊、權限管理
根據(jù)用戶登錄狀態(tài)管理其瀏覽路由的權限是應用中很常見的功能
class App extends React.Component {
render() {
return (
<Provider store={store}>
<BrowserRouter>
<Switch>
<Route path="/auth" component={UnauthorizedLayout} />
<AuthorizedRoute path="/app" component={PrimaryLayout} />
</Switch>
</BrowserRouter>
</Provider>
)
}
}
可以結合 react redux
設計權限管理功能,<AuthorizedRoute>
組件先檢測當前的登錄狀態(tài)掏熬,
如果是正在登錄佑稠,則顯示 Loading...
如果已經(jīng)登錄則,則跳轉到到 <PrimaryLayout>
組件中
如果未登錄旗芬,則跳轉到登錄頁
class AuthorizedRoute extends React.Component {
componentWillMount() {
getLoggedUser()
}
render() {
const { component: Component, pending, logged, ...rest } = this.props
return (
<Route {...rest} render={props => {
if (pending) return <div>Loading...</div>
return logged
? <Component {...this.props} />
: <Redirect to="/auth/login" />
}} />
)
}
}
const stateToProps = ({ loggedUserState }) => ({
pending: loggedUserState.pending,
logged: loggedUserState.logged
})
export default connect(stateToProps)(AuthorizedRoute)
Other mentions 其他
<Link> vs <NavLink>
這兩個功能一樣舌胶,都是路由跳轉,但是NavLink有一個屬性用來顯示跳轉選中的樣式疮丛,activeStyle屬性幔嫂,寫顯示高亮樣式的辆它,接收一個對象{}
在我們路由導航有一個to屬性
to屬性是我們路由的要跳轉的路徑:
import React from 'react'
import { NavLink } from 'react-router-dom'
const PrimaryHeader = () => (
<header className="primary-header">
<h1>Welcome to our app!</h1>
<nav>
<NavLink to="/app" exact activeClassName="active">Home</NavLink>
<NavLink to="/app/users" activeClassName="active">Users</NavLink>
<NavLink to="/app/products" activeClassName="active">Products</NavLink>
</nav>
</header>
)
export default PrimaryHeader
Dynamic Routes 動態(tài)路由
在 V4中最好的一部分改變是可以在所有地方包含 <Route>
, 它只是一個 React 組件履恩。
路由將不再是神奇的東西锰茉,我們可以用在任何地方,試想一下切心,當滿足條件時飒筑,整個路由都可以被路由到。
在這些條件不滿足時绽昏,我們可以移除那些路由协屡,甚至,可以嵌套路由全谤。
React Router 4
變得更好用是因為這只是一個 Just Components?肤晓。