安装
React Router官方git上发布了5个相关的包
|
包
|
文档地址
|
描述
|
| --- | --- | --- |
| react-router | https://reacttraining.com/react-router/core/guides/quick-start | React Router的核心包,提供核心的路由组件与函数 |
| react-router-dom | https://reacttraining.com/react-router/web/guides/quick-start | 用于 DOM 绑定的 React Router |
| react-router-native | https://reacttraining.com/react-router/native/guides/quick-start | 用于 React Native 的 React Router |
| react-router-redux | https://github.com/ReactTraining/react-router/tree/master/packages/react-router-redux#readme | React Router 和 Redux 的集成 |
| react-router-config | https://github.com/ReactTraining/react-router/tree/master/packages/react-router-config#readme | 静态路由配置的小助手 |
在web项目中(基于浏览器),react-router、react-router-dom两个中只要引用一个就行了,不同之处就是后者比前者多出了<Link>、<NavLink> 这样的 DOM 类组件。因此建议项目中引用 react-router-dom。
示例
|
import React ``from
'react'
import ``{
BrowserRouter ``as
Router``,
Route``,
Link
}
from
'react``-``router``-``dom'
const BasicExample ``=
(``)
=``>
(
<``Router``>
<``div``>
<``ul``>
<``li``>``<``Link ``to``=``"/"``>``Home``<``/``Link``>``<``/``li``>
<``li``>``<``Link ``to``=``"/about"``>``About``<``/``Link``>``<``/``li``>
<``li``>``<``Link ``to``=``"/topics"``>``Topics``<``/``Link``>``<``/``li``>
<``/``ul``>
<``hr``/``>
<``Route exact ``path``=``"/"
component``=``{``Home``}``/``>
<``Route ``path``=``"/about"
component``=``{``About``}``/``>
<``Route ``path``=``"/topics"
component``=``{``Topics``}``/``>
<``/``div``>
<``/``Router``>
)
export default BasicExample
|
Router组件
React Router 4 提供了几种Router组件,BrowserRouter、HashRouter、MemoryRouter、StaticRouter。
history
要想明白这3种组件的区别,我们先从history说起。histoty 是 React Router 4 的两大重要依赖之一(另一个当然是 React 了),在不同的 javascript 环境中, history 以多种形式实现了对会话(session)历史的管理。
我们会经常使用以下术语:
- "browser history" - history 在 DOM 上的实现,用于支持 HTML5 history API 的浏览器
- "hash history" - history 在 DOM 上的实现,用于旧版浏览器。
- "memory history" - history 在内存上的实现,用于测试或非 DOM 环境(例如 React Native)。
4.0之前版本的react-router针对三者分别实现了createHashHistory、createBrowserHistory和create MemoryHistory三个方法来创建三种情况下的history。到了4.0版本,在react-router-dom中直接将这三种history作了内置,于是我们看到了BrowserRouter、HashRouter、MemoryRouter这三种Router,当然,你依然可以使用React-router中的Router,然后自己通过createHistory来创建history来传入。
MemoryRouter
在内存中保存“URL”信息,不会修改浏览器的地址栏,往往用于React Native或测试环境等非浏览器环境。
StaticRouter
从不修改路由
HashRouter
这是之前2.X版本处理浏览器路由的方式,基于url的hash段
|
http:``//localhost``:3333/``#/login
|
BrowserRouter
官方推荐使用的方式,基于url的pathname段
|
http:``//localhost``:3333``/login
|
在react-router 4.0 的文档中有这样一段话:
使用 hash 的方式记录导航历史不支持 location.key 和 location.state。 在以前的版本中,我们为这种行为提供了 shim,但是仍有一些问题我们无法解决。 任何依赖此行为的代码或插件都将无法正常使用。 由于该技术仅用于支持传统的浏览器,因此在用于浏览器时可以使用 <BrowserHistory> 代替。
需要注意的是使用<BrowserRouter>后会出现 2 个问题:
如果你不是通过服务器启动应用,因为chrome自身的安全机制,在本地环境下根本不能用chrome玩。这个不关键,我本地测试换个浏览器还不行么,本地起个服务器也不麻烦。
关键问题,刷新就是404。原因很简单,BrowserRouter 和 HashRouter 完全不同,前者利用H5的 history 接口,前台路由就是后台收到的路由,例如上面的登录页,在进行刷新时,会去请求服务器的/login资源,但是服务器上根本没这个资源,那么将返回404。所以在使用BrowserRouter时,服务器需要做一些修改,修改的思想就是当收到请求的url不是功能性的,而是前端路由时,重新加载入口html。
-
Apache -> mod_rewrite
Nginx -> rewrite
Webpack Dev Server -> historyApiFallback
Express/Koa/Hapi/etc. -> a wildcard route to your index.html
下面列举几个例子
nodejs服务器
|
app.use(express.static(path.join(__dirname, 'build')));
-app.get('/', function (req, res) {
+app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
|
apache服务器,.htaccess文件
|
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
|
gulp + browserSync
|
gulp.task(``'browserSync'``, ``function
() {
var
proxyOptions = url.parse(``'[http://k1268.mlamp.co/tuning'](http://k1268.mlamp.co/tuning')``);
proxyOptions.route = ``'/tuning'``;
browserSync.init({
server: {
baseDir: ``'./dist/'``,
middleware: [proxy(proxyOptions)],
routes: {
"/login"``: ``"./dist/"``,
"/app"``: ``"./dist/"``,
"/app/todos"``: ``"./dist/"``,
}
},
port: 3333,
open: ``false``,
reloadOnRestart: ``true
})
// 监听模板html变化
gulp.watch(config.pug, [``'pug'``])
// 监听sass变化
gulp.watch(config.sass, [``'styles'``])
// 监听image变化
gulp.watch(config.image, [``'images'``])
})
|
<Router>组件下只允许存在一个子元素,如存在多个则会报错。
Route组件
<Route>组件是React Router中主要的结构单元。在任意位置只要匹配了URL的路径名(pathname)你就可以创建<Route>元素进行渲染。
<Route>是如何渲染的?
当一个路由的path匹配成功后,路由用来确定渲染结果的参数有三种。只需要提供其中一个即可。
- component : 一个React组件。当带有component参数的route匹配成功后,route会返回一个新的元素,其为component参数所对应的React组件(使用React.createElement创建)。
- render : 一个返回React element的函数。当匹配成功后调用该函数。该过程与传入component参数类似,并且对于行级渲染与需要向元素传入额外参数的操作会更有用。
- children : 一个返回React element的函数。与上述两个参数不同,无论route是否匹配当前location,其都会被渲染。
|
<Route path=``'/page'
component={Page} />
const
extraProps = { color: ``'red'
}
<Route path=``'/page'
render={(props) => (
<Page {...props} data={extraProps}/>
)}/>
<Route path=``'/page'
children={(props) => (
props.match
? <Page {...props}/>
: <EmptyPage {...props}/>
)}/>
|
<Route component>的优先级要比<Route render>高,所以不要在同一个<Route>中同时使用这两个属性。
那么Route是如何知道url更新了然后进行重新匹配和渲染的呢?
Route的实现机制:在一个web应用中,改变url无非是2种方式,一种是利用超链接进行跳转,另一种是使用浏览器的前进和回退功能。前者的在触发Link的跳转事件之后触发,而后者呢?Route利用的是我们上面说到过的history的listen方法来监听url的变化。为了防止引入新的库,Route的创作者选择了使用html5中的popState事件,只要点击了浏览器的前进或者后退按钮,这个事件就会触发。
属性说明
-
path
任何可以被 path-to-regexp解析的有效 URL 路径,如果path没有赋值,那么此Route就是默认渲染的。
-
exact
精确匹配,如果为 true,path 为 '/one' 的路由将不能匹配 '/one/two'。
-
strict
对路径末尾斜杠的匹配。如果为 true。path 为 '/one/' 将不能匹配 '/one' 但可以匹配 '/one/two'。
如果要确保路由没有末尾斜杠,那么 strict 和exact 都必须同时为 true
Link组件
如果使用锚点元素实现页面间的切换,在每次点击时页面将被重新加载。React Router提供了<Link>组件用来避免这种状况的发生。当你点击<Link>时,URL会更新,组件会被重新渲染,但是页面不会重新加载。
参数如下:
|
static
propTypes = {
onClick: PropTypes.func,
target: PropTypes.string,
replace: PropTypes.bool,
to: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object
]).isRequired
}
|
replace:跳转的链接是否覆盖history中当前的url,若为true,新的url将会覆盖history中的当前值,而不是向其中添加一个新的。
to:指定需要定位的页面。它的值即可是字符串也可是location对象(包含pathname,search,hash与state属性)。如果其值为字符串将会被转换为location对象。
|
<Link to={{ pathname: ``'/roster/7'
}}>Player #``7``</Link>
|
NavLink组件
<NavLink> 和 <Link> 功能相似,会在匹配上当前URL的时候给已经渲染的元素添加样式参数,组件属性:
- activeClassName(string):设置选中样式,默认值为 active;
- activeStyle(object):当元素被选中时, 为此元素添加样式;
- exact(bool):为 true 时, 只有当地址完全匹配 class 和 style 才会应用;
- strict(bool):为 true 时,在确定位置是否与当前 URL 匹配时,将考虑位置 pathname 后的斜线;
- isActive(func):判断链接是否激活的额外逻辑的功能;
Switch组件
React Router 4 的路由默认为“包含”的,这意味着多个 <Route> 可以同时进行匹配和渲染。如上面示例中
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/topics" component={Topics}/>
在“/”路由中使用exact进行了精确的路径匹配,如果删掉exact属性的话,那么在访问/About时,将会同时渲染Home组件和About组件,在访问/Topics时,将会同时渲染Home组件和Topics组件。
这种设计,允许我们以多种方式将多个<Route>组合到我们的应用程序中,例如侧栏(sidebars),面包屑(breadcrumbs),bootstrap tabs等等。
如果我们只需要在路由列表里匹配一个路由,这时可以使用 <Switch> 来启用排他路由,在给定的 <Switch> 路由中只有一条将渲染:
|
const
BasicExample = () => (
<Router>
<div>
<ul>
<li><Link to=``"/"``>Home</Link></li>
<li><Link to=``"/about"``>About</Link></li>
<li><Link to=``"/topics"``>Topics</Link></li>
</ul>
<hr/>
<Switch>
<Route path=``"/"
exact component={Home}/>
<Route path=``"/about"
component={About}/>
<Route path=``"/topics"
component={Topics}/>
</Switch>
</div>
</Router>
)
|