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 和用法,需要学习的还有很多,这里只是开始。