React Router @4.0初学

安装

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 个问题:

  1. 如果你不是通过服务器启动应用,因为chrome自身的安全机制,在本地环境下根本不能用chrome玩。这个不关键,我本地测试换个浏览器还不行么,本地起个服务器也不麻烦。

  2. 关键问题,刷新就是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>

)

|

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • 如果你已经是一个正在开发中的react应用,想要引入更好的管理路由功能。那么,react-router是你最好的选...
    夏尔先生阅读 31,098评论 7 47
  • React项目的可用的路由库React-Router,当然这也是官方支持的。它也分为:*react-router ...
    落寒_49c6阅读 1,113评论 0 0
  • React Router教程 React项目的可用的路由库是React-Router,当然这也是官方支持的。它也分...
    __db84阅读 728评论 0 0
  • React Router教程 React项目的可用的路由库是React-Router,当然这也是官方支持的。它也分...
    CLYDE_6715阅读 266评论 0 0
  • React Router教程 React项目的可用的路由库是React-Router,当然这也是官方支持的。它也分...
    应晨皓阅读 428评论 0 0