新手理解react-router关键点解析

1 为什么需要使用react-router

当你写了很多react组件后,想要实现不同组件之间的切换和跳转的时候,react-router就派上用场了。

2 使用react-router-dom还是react-router

两者区别不大,一般只使用react-router-dom就能满足我们的需要。

3 安装方法

npm install --save react-router-dom

4 如何使用

使用前要先引入

import { BrowserRouter as Router, Route, Link } from 'react-router-dom'//这里将BrowserRouter重命名为Router

使用举例


先打开本地服务器,如果不懂怎么做,请看我的另一篇文章http://www.jianshu.com/p/d08db717a66f

<Router>
  <div>
    <ul>
      <li><Link to="/">主页</Link></li>
      <li><Link to="/hot">热门</Link></li>
      <li><Link to="/zhuanlan">专栏</Link></li>
    </ul>
    <hr/>
    <Route  exact path="/" component={App}></Route>
    <Route path="/hot" component={Hot} ></Route>
    <Route path="/zhuanlan" component={Zhuanlan}></Route>
  </div>
</Router>

<Router></Router>相当于一个盒子,里面只能包含一个子元素。

react-router4之后,<Router></Router>标签里面可以包含任何html标签和react组件。

然而并不是react-route的其他标签必须包在Router里面,比如只要通过import { Route, Link} from 'react-route-dom'引入,可以随意单独使用Route和Link标签。

<Link></Link>标签和<a></a>标签类似,点击<Link></Link>标签中的元素可以实现组件跳转。跳转到哪个组件要看path的值"/"代表根路径,相当于localhost:8080这个路径,我们发现有一个<Route></Route>的path属性和这个Link标签的path值相同,当用户点击Link标签时,会触发和它具有相同path值的Route的component渲染,并且浏览器的网址那里的url变成他们的path值代表的路径。

因此,我们可以理解,“路由”就是要实现url跳转,注意不要和直接打开html文件哪个本地文件路径搞混了,这里改变的是网址URL,就是你的path值,前面加上localhost:8080。

那么问题来了,url和文件路径的区别是什么?

我们以前练习的时候,打开我们的index.html是手动直接打开的,它在浏览器中显示的路径就是以我们的电脑哪个磁盘开始的资源路径,就是这个文件在电脑中的位置。

url路径不同于资源路径,我们的组件Hot的url路径是localhost:8080/hot,这是我们自己定义的,和Hot组件在电脑中的位置无关,反正只要我们在<Route></Route>中定义了这个component的path,那么这个组件的url就确定了,不用管它在电脑中的位置,当然,在当前文件中必须先引入这个组件,还是按电脑中的相对路径来的。所以,你理解资源路径和url的区别了吗?

5 history的理解

如果你用过老版本的react-router,你一定知道history。history是用来兼容不同浏览器或者环境下的历史记录管理的,当我跳转或者点击浏览器的后退按钮时,history就必须记录这些变化。

browserHistory h5的history兼容性不好,需要后端支持,在渲染组件的时候转成hashHistory。

<Router history={browserHistory} routes={routes} />,
这种情况需要对服务器改造。否则用户直接向服务器请求某个子路由,会显示网页找不到的404错误。

browserHistory 模式下,URL 是指向真实 URL 的资源路径,当通过真实 URL 访问网站的时候(首页),这个时候可以正常加载我们的网站资源,而用户在非首页下手动刷新网页时,由于路径是指向服务器的真实路径,但该路径下并没有相关资源(因为url路径是path中设置的路径,并不是资源路径),用户访问的资源不存在,返回给用户的是 404 错误

官方推荐使用browserHistory

History API 提供了 pushState() 和 replaceState() 方法来增加或替换历史记录。

而 hash 没有相应的方法,所以并没有替换历史记录的功能。但 react-router 通过 polyfill 实现了此功能,具体实现没有看,好像是使用 sessionStorage。

另一个原因是 hash 部分并不会被浏览器发送到服务端,也就是说不管是请求

http://domain.com/index.html#foo 还是http://domain.com/index.html#bar ,服务只知道请求了 index.html 并不知道 hash 部分的细节。而 History API 需要服务端支持,这样服务端能获取请求细节。

还有一个原因是因为有些应用会忽略 URL 中的 hash 部分。

对于初学者,我推荐先使用<Router history={hashHistory}>,并且在引入Router时使用HashHistory as Router代替BrowserHistory as Router,以免出现不必要的麻烦。

6 react-router4路由嵌套

什么是路由嵌套

路由嵌套,顾名思义就是路由/URL路径的嵌套,比如,若Hot组件的路由是localhost:8080/hot,如果我们想要得Hot组件添加一个子组件Girl,每次我们渲染Girl的时候,Hot也会自动和他一起渲染,那么可以这样写

//父组件中
<Router>
  <div>
    <Route  exact path="/" component={App}></Route>
    <Route path="/hot" component={Hot} ></Route>
    <Route path="/zhuanlan" component={Zhuanlan}></Route>
  </div>
</Router>

//子组件中
    <Route path="/hot/girl" component={Girl} ></Route>  

理解<Route></Route>

在react-router4中,将他看做一个类似于组件的东西,你想在哪里渲染组件,就把他写在哪里

//入口组件app.js
            <Router history={hashHistory}>
                <div>
                    <Route exact path="/" component={PCIndex}></Route>              
                    <Route path="/hf" component={HeaderAndFooter}></Route>
                </div>  
            </Router>

//HeaderAndFooter组件
            <div>
                <PCHeader />
                <Route path="/hf/paper" component={BodyPaper}></Route>
                <Route path="/hf/people" component={BodyPeople}></Route>
                <BodyFooter />
            </div>

路由对应:

localhost:8080----渲染PCIndex组件

localhost:8080/hf----渲染HeaderAndFooter组件

localhost:8080/hf/paper----同时渲染BodyPaper和HeaderAndFooter组件组件,并且BodyPaper组件在PCHeader组件和BodyFooter组件的中间

localhost:8080/hf/people----同时渲染BodyPeople和HeaderAndFooter组件组件,并且BodyPeople组件在PCHeader组件和BodyFooter组件的中间

7 组件路由参数传递match和:id的理解

match参数的理解

通过Route路由的组件,可以拿到一个match参数,这个参数是一个对象,其中包含几个数据:

isExact:这个关键字表示是为作全等匹配,比如,写了exact,“/”只能匹配PCIndex组件,而不写那就问题大了,在localhost:8080路径下,还可以匹配到HeaderAndFooter组件,并将其渲染。

params:path中包含的一些额外数据

path:Route组件path属性的值

url:实际url的hash值

示例

const HeaderAndFooter = ({match}) => (//{match}要先引入
    <div>
        <PCHeader />
        <Route path={`${match.url}/paper`} component={BodyPaper}></Route>
        <Route path="/hf/people" component={BodyPeople}></Route>
        <BodyFooter />
    </div>
)

export default HeaderAndFooter;

${match.url}获取到的路径就是HeaderAndFooter的path路径

这里用到了es6的模板字符串功能,两个反单引号括起来的字符串,里面可以放js语句,比如变量,但需要将变量名写在${}之中

模板字符串之中还能调用函数let msg = Hello, ${place};

:id的理解

:id其实是官网文档中的一种写法,你也可以任意写这个参数,它放在url中,也是用来传递参数的。它不是要参与url路由,react-router会通过props.params传递给组件,id表示参数变量,id有实际值将替换掉 :id ,变为实际参数。

比如:

当我们请求/home/123/app/456的时候, 路由就会匹配到/home/:userId/app/:appId

其中params就是指的上面的userId 和 appId

转换成json就是{userId: 123, appId: 456}

利用这种参数传值:

示例

<Route path="/hf/people" component={BodyPeople}></Route>
<Route path={`${match.url}/:id`} component={BodyPaper}></Route>

当我们访问localhost:8080/fh/people的时候,就会渲染BodyPeople组件,people也会替换了url中的:id,渲染BodyPaper组件。

可以用Switch解决这个问题,Switch下每次只匹配一个路由,并且将这种含参数的url往下写也是一个很好的习惯。

 <Switch>
    {/* 用了Switch 这里每次只匹配一个路由,所有只有一个节点。 */}
    <Route path="/about" component={About}/>
    <Route path="/:user" component={User}/>
    <Route component={NoMatch}/>
  </Switch>

综合示例

  //父组件中
    const Hot=({match})=>(<div>
    
    <h2>热门</h2>
    <Link to={`${match.url}/article`}>文章</Link>
    <Link to={`${match.url}/qa`}>问答</Link>
    <Link to={`${match.url}/news`}>新闻</Link>
    <hr/>
    <Route path={`${match.url}/:type`} component={Content}></Route>
    
    </div>)
    //子组件中
    const Content=({match})=>(
    <div>
      <h2>热门子目录</h2>
      <p>{match.params.type}</p>
    </div>
)

可以发现match.params.type轻松取到了url中的参数。

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

推荐阅读更多精彩内容