说到 React 我们一定离不开和 Router 打交道。不管 Vue Router 和 React Router ,他们的原理都是差不多的。这篇文章会从一个简单的例子一直拓展到真正的 React Router。
React-router
React Router 是专为 React 设计的路由解决方案。它利用HTML5 的history API,来操作浏览器的 session history (会话历史)。
React 路由
React Router被拆分成四个包:
react-router
实现了路由的核心功能。react-router-dom
基于react-router,加入了在浏览器运行环境下的一些功能。react-router-native
基于react-router,加入了 React Native 运行环境下的一些功能react-router-redux
React Router 和 Redux 的集成react-router-config
react-router提供核心的路由组件与函数。react-router-config用来配置静态路由(还在开发中。
进行网站(将会运行在浏览器环境中)构建,我们应当安装react-router-dom。因为react-router-dom已经暴露出react-router中暴露的对象与方法,因此你只需要安装并引用react-router-dom即可。
安装
如上所说,我们使用react开发web应用,所以只需要安装react-router-dom。
npm install react-router-dom --save
理解和使用react-router
BrowserRouter
,这是对Router
接口的实现。使得页面和浏览器的history
保持一致。如:window.location
。HashRouter
,和上面的一样,只是使用的是url的hash部分,比如:window.location.hash
。MemoryRouter
,NativeRouter
,处理react native内的路由。StaticRouter
,处理静态路由,和v3一样。
BrowserRouter vs HashRouter
在react-router的各种router中,<BrowserRouter>
和<HashRouter>
是可以在浏览器中使用的。如果你使用的是一个非静态的站点、要处理各种不同的url那么你就需要使用BrowserRouter
。相反的如果你的server只处理静态的url,那么就使用HashRouter
。
理解和使用Router
在4.0之前版本的 API 中,<Router>
组件的 children 只能是 React Router 提供的各种组件,如<Route>
、<IndexRoute>
、<Redirect>
等。而在 React Router 4 中,你可以将各种组件及标签放进 <Router>
组件中,他的角色也更像是 Redux 中的 <Provider>
。不同的是<Provider>
是用来保持与 store 的更新,而<Router>
是用来保持与 location 的同步.
// 示例1
<Router>
<div>
<ul>
<li><Link to="/">首页</Link></li>
<li><Link to="/about">关于</Link></li>
<li><Link to="/topics">主题列表</Link></li>
</ul>
<hr/>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/topics" component={Topics}/>
</div>
</Router>
Router是所有路由组件共用的底层接口,一般我们的应用并不会使用这个接口,而是使用高级的路由:
<BrowserRouter>
:这是一个路由管理器,使用 HTML5 提供的 history API 来保持 UI 和 URL 的同步;<HashRouter>
:使用 URL 的 hash (例如:window.location.hash) 来保持 UI 和 URL 的同步;<MemoryRouter>
:能在内存保存你 “URL” 的历史纪录(并没有对地址栏读写);<NativeRouter>
:为使用React Native提供路由支持;<StaticRouter>
:从不会改变地址;
理解和使用Route
<Route>
组件是react router v4里最有用的组件。背后的使用哲学也很简单,无论何时你需要在匹配某个路径的时候绘制一个组件,那么就可以使用Route
组件。
Route
组件可以使用如下的属性:
path
属性,字符串类型,它的值就是用来匹配url的。component
属性,它的值是一个组件。在path匹配成功之后会绘制这个组件。exact
属性,为true时,则要求路径与location.pathname必须完全匹配。strict
属性,为true的时候,有结尾斜线的路径只能匹配有斜线的location.pathname。
还有其他的一些属性,可以用来代替component
属性。
render
属性,一个返回React组件的方法。传说中的rencer-prop就是从这里来的。children
属性,返回一个React组件的方法。只不过这个总是会绘制,即使没有匹配的路径的时候。
多数的时候是用component
属性就可以满足。但是,某些情况下你不得不使用render
或children
属性。
- match
- location
- history
const FadingRoute = ({ component, ...rest }) => (
<Route {...rest} render={(props) => (
<FadeIn>
<componnet {...props} />
</FadeIn>
)} />
)
<Router>
<div>
<Route exact path="/" component={Home}/>
<Route path="/news" component={NewsFeed}/>
<Route path="/user" render={()=><div>UserPage</div>} />
<FadingRoute path="/others" component={Something} />
</div>
</Router>
// <Route component>的优先级要比<Route render>高,所以不要在同一个<Route>中同时使用这两个属性
exact配置:
路径 | location.pathname | exact | 是否匹配 |
---|---|---|---|
/my | /my/one | true | 否 |
/my | /my/one | false | 是 |
strict配置:
路径 | location.pathname | strict | 是否匹配 |
---|---|---|---|
/my/ | /my | true | 否 |
/my/ | /my/ | true | 是 |
/my/ | /my/one | true | 是 |
理解并使用Link
使用Link
可以在React应用的不同页面之间跳转。与unclor会重新加载整个页面不同,Link
只会重新加载页面里和当前url可以匹配的部分。
- to(string/object):要跳转的路径或地址;
- replace(bool):为 true 时,点击链接后将使用新地址替换掉访问历史记录里面的原地址;为 false 时,点击链接后将在原有访问历史记录的基础上添加一个新的纪录。默认为 false;
import { Link } from 'react-router-dom';
<Link to={{
pathname: '/me',
search: '?sort=asc',
hash: '#hash',
state: { fromHome: true }
}} />
实例:
import { Link } from 'react-router-dom';
const Nav = () => (
<Link to='/'>Home</Link>
<Link to="/about">About</Link>
<Link to="/other">Other</Link>
<Link to="/user">User</Link>
<Link to="/my">My</Link>
// 禁止跳转
<Link to='##'>Home</Link> // 意想不到的效果
);
什么是NavLink
NavLink
是Link
的一个子类,在Link组件的基础上增加了绘制组件的样式,比如:
- activeClassName(string):设置选中样式,默认值为 active;
- activeStyle(object):当元素被选中时, 为此元素添加样式;
- exact(bool):为 true 时, 只有当地址完全匹配 class 和 style 才会应用;
- strict(bool):为 true 时,在确定位置是否与当前 URL 匹配时,将考虑位置 pathname 后的斜线;
- isActive(func):判断链接是否激活的额外逻辑的功能;
// activeClassName选中时样式为selected
<NavLink
to="/faq"
activeClassName="selected"
>FAQs</NavLink>
// 选中时样式为activeStyle的样式设置
<NavLink
to="/faq"
activeStyle={{
fontWeight: 'bold',
color: 'red'
}}
>FAQs</NavLink>
// 当event 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>
Switch的用法
组件和语法中的 switch
功能类似,执行第一个匹配的路由。这个逻辑很直观也就是排他性,主要解决使用多个 <Route>
时多个路由同时匹配的问题。<Switch>
的独特之处是独它仅仅渲染一个路由。相反地,每一个包含匹配地址(location)的<Route>
都会被渲染。
实例:
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
如果现在的URL是/about,那么
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
</Switch>
使用Redirect组件实现重定向
无论何时你要重定向到另外一个地址的时候,都可以使用Redirect
组件:
<Redirect to="register" />
浏览器历史
react router v4中,提供了一个history
对象。这个对象包含了多个api,可以用来操作浏览器历史等。
你也可以在React应用里使用history对象的方法:
goMy = () => {
this.props.history.push("/my")
}
render() {
return <div onClick={this.goMy}>我的</div>
}
用另外的方法可以写成:
<Link to="/my" />
<Redirect to="my" />
使用react router dom实现你的第一个demo
现在我们用react router dom来实现第一个demo。
首先,引入必要的组件。比如:Route
和BrowserRouter
。
写App组件
import { BrowserRouter, Route } from 'react-router-dom';
const App = () => (
<BrowserRouter>
<BaseLayout />
</BrowserRouter>
)
render(<App />, document.getElementById('root'));
我们来已创建的组件:
const BaseLayout = () => (
<div className="base">
<header>
<p>React Router v4 Browser Example</p>
<nav>
<ul>
<li><Link ="/">Home</Link></li>
<li><Link ="/about">About</Link></li>
<li><Link ="/me">Profile</Link></li>
<li><Link ="/login">Login</Link></li>
<li><Link ="/register">Register</Link></li>
<li><Link ="/contact">Contact</Link></li>
</ul>
</nav>
</header>
<div className="container">
<Route path="/" exact component={HomePage} />
<Route path="/about" component={AboutPage} />
<Route path="/contact" component={ContactPage} />
<Route path="/login" component={LoginPage} />
<Route path="/register" component={RegisterPage} />
<Route path="/me" component={ProfilePage} />
</div>
<footer>
React Router v4 Browser Example (c) 2017
</footer>
</div>
);
同时我们用react router v4里的Link和NavLink组件。
const BaseLayout = () => (
<div className="base">
<header>
<p>React Router v4 Browser Example</p>
<nav>
<ul>
<li><Link ="/">Home</Link></li>
<li><Link ="/about">About</Link></li>
<li><Link ="/me">Profile</Link></li>
<li><Link ="/login">Login</Link></li>
<li><Link ="/register">Register</Link></li>
<li><Link ="/contact">Contact</Link></li>
</ul>
</nav>
</header>
<div className="container">
<Route path="/" exact component={HomePage} />
<Route path="/about" component={AboutPage} />
<Route path="/contact" component={ContactPage} />
<Route path="/login" component={LoginPage} />
<Route path="/register" component={RegisterPage} />
<Route path="/me" component={ProfilePage} />
</div>
<footer>
React Router v4 Browser Example (c) 2017
</footer>
</div>
);
参考地址: