React Router V5 使用总结

8,320

一、先简单交代几句

对于之前没有接触过 React Router 的同学来说,一定要注意:最新的React Router版本是 V5 。除此之外,还有 V2 V3 V4 版本。其中V4和V5版本的用法和理念基本上是一致的,但是和之前的V2、V3版本有较大差异。

所以在学习之前一定要弄清楚自己使用的是哪一个版本,如果是V4或者V5,V4和V5两个版本的文档笔记都可以参考;如果你用的是V2或者V3,那么一定要找到对应的文档笔记。

在我学习React Router的时候,使用的是V5,所以这篇笔记也是对 React Router V5 的一些总结。如果你是一名React小白,我想通过这篇笔记,你可以基本会使用React Router。如果你想更深层次地理解React Router,可以访问:reacttraining.com/react-route…

二、React Router 的基本使用

1. 安装

在V4和V5版本中,React Router分成了两个大的方向:React Web Router 和 React Native Router 。如果你是创建的React Web应用,就使用React Web Router ,这里我们使用的就是这个Router,所以执行以下命令进行安装:

npm install --save react-router-dom

2. 在React项目中配置路由

想要在React项目中使用路由,必不可少的有两个组件(component): BrowserRouterRoute 。在React项目中,通过以下命令引入这两个组件:

import { BrowserRouter, Route } from "react-router-dom";

BrowserRouter 组件是React Router的核心,Route组件是React Router的具体配置。举个例子来说:BrowserRouter 组件就像是一个文具盒,Route组件就像是一件件文具一样,需要放在这个盒子里。这样我们在使用文具的时候,只需要打开文具盒,从里面取出即可。

了解了这层关系,我们就可以在React中配置路由了,配置非常简单,示例代码如下:

// React 应用中的 App.js 文件

import React from 'react';
import { BrowserRouter, Route } from 'react-router-dom'
import Set from './views/set/Set'
import Help from './views/help/Help'

class App extends React.Component {
    render() {
        return (
            <BrowserRouter>
                <Route path="/help" component={Help} />
                <Route path="/set" component={Set} />
            </BrowserRouter>
        );
    }
}

export default App;

在App.js文件中配置完车之后,然后在React入口文件中(一般是index.js文件),引入App.js文件并挂载到页面上,示例代码如下:

// React 应用中的入口文件 index.js 

import React from 'react'
import { render } from 'react-dom'
import App from './App'

render((
   <App />
), document.getElementById('root'))

挂载完成之后,通过npm run start 等命令启动本地开发服务器,就可以通过路由访问我们的React项目了。实例如下:

简单介绍一下以上代码中的路由配置规则,以这条路由配置为例:

<Route path="/help" component={Help} />

Help 是我们之前定义好的一个React组件,该组件的定义代码如下:

import React, { Component } from 'react'

class Help extends Component {
    render() {
        return (
            <div className="help-box">
                帮助与反馈 - 页面
            </div>
        );
    }
}

export default Help;

当我们在浏览器地址栏中输入 http://localhost:3000/help 的时候,React Router 会匹配到 <Route path="/help" component={Help} /> 这一条记录,然后就会在当前位置渲染对应的component。

注意是当前位置,说得更通俗一点:就是使用将Help组件中的代码替换掉 <Route path="/help" component={Help} /> 代码,进而渲染出路由对应的component。关于这一点,后面会有更详细的解释。

3. 在React中通过链接跳转路由

通过上面的配置,我们已经可以通过输入URL来跳转路由,但是更多情况下,我们希望可以通过点击页面上的链接进行路由的跳转,比如以下的示例:

想要实现这一点,我们只需要引入 Link 这个组件即可,具体代码如下:

// React 应用中的 App.js 文件

import React from 'react';
import { BrowserRouter, Route, Link } from 'react-router-dom'   // 引入 Link 组件
import Set from './views/set/Set'
import Help from './views/help/Help'

class App extends React.Component {
    render() {
        return (
            <BrowserRouter>
            	{/* 注意 Link 组件一定要位于 BrowserRouter 组件中 */}
                <ul>
                    <li><Link to="/help">Help</Link></li>
                    <li><Link to="/set">Set</Link></li>
                </ul>
                
                <Route path="/help" component={Help} />
                <Route path="/set" component={Set} />
            </BrowserRouter>
        );
    }
}

export default App;

三、React Router 的进阶使用

现在我们已经掌握了React Router的基本使用,但是这个时候我们掌握的知识还不足以让我们熟练地使用它,所以下面为大家介绍React Router更多内容。

1. Route 的匹配规则

在对Route进行配置的时候,我们可以传以下参数:path、exact、component、render、children 。这些参数都不是必须的,也就是说,我们有很多中配置Route的方式,常见的有以下几种:

<BrowserRouter>
    <Route component={Wallet} />
    <Route path="/" component={Index} />
    <Route exact path="/" component={Index} />
    <Route path="/help" component={Help} />
    <Route path="/render" render={ () => { return <h1>我是匹配到的路由</h1> } } />
</BrowserRouter>

这里分别介绍以上五种Route的配置方式:

  • <Route component={Wallet} />

    在配置Route的时候没有指定 path 属性,这时只要你打开项目,无论你访问什么路径,这个Route都会匹配到。

  • <Route path="/" component={Index} />

    配置Route的时候,指定 path="/" ,和上面配置的效果一样,只要你打开项目,无论你访问什么路径,这个Route都会匹配到。这种配置方式我们成为 "非严格匹配" ,你在项目中访问的任何一个路径,里面都会包含path="/" 的路径。所以无论访问什么路径,这个Route都会匹配到。

  • <Route exact path="/" component={Index} />

    和上面一条的配置方式不同,这里在配置Route的时候,传入了 exact 属性,说明这个配置方式是 "严格匹配" ,只有当我们访问项目的根路径的时候,才会匹配到这个Route。比如:localhost:3000/ 。

  • <Route path="/help" component={Help} />

    一条很常规的Route配置方式,当我们访问"/help"路径的时候,匹配到这个Route,进而渲染出对应的component。

  • <Route path="/render" render={ () => { return <h1>我是匹配到的路由</h1> } } />

    和上一条路由配置不同的是,这里没有component属性,而是换成了render属性。该属性是一个函数,当匹配到这个Route的时候,页面将会渲染出这个函数返回的内容。

2. Switch 组件的使用

Switch组件的使用其实非常简单,举个例子:如果说BrowserRouter组件是一个大的文具盒的话,那么Switch组件就是这个大文具盒中的一个小袋子,Route组件就是这个小袋子中的一支铅笔,我们需要铅笔的时候,直接从这个小袋子里面取出一支即可。注意:是最多只能取出一支铅笔。

也就是说,当进行路由匹配的时候,一旦匹配到了Switch组件中的一个Route,那么就不会再继续匹配。比如以下实例:

<BrowserRouter>
    <Switch>
        <Route component={Wallet} />
        <Route path="/" component={Index} />
        <Route path="/help" component={Help} />
        <Route path="/render" render={() => { return <h1>我是匹配到的路由</h1> }} />
    </Switch>
</BrowserRouter>

如果我们访问 "localhost:3000/help" 路径,虽然前三个Route都匹配,但是页面只会渲染第一个匹配到的Route,其他的都被忽略。看到这里你可能会问,这个组件有什么作用呢?可以在以下场景中发挥作用:如果当前路径没有匹配到任何Route的时候,路由跳转到 404 页面,那么就可以这样写:

<BrowserRouter>
    <Switch>
        <Route path="/set" component={Set} />
        <Route path="/help" component={Help} />
        <Route path="/render" render={() => { return <h1>我是匹配到的路由</h1> }} />
        <Route component={NotFound} />
    </Switch>
</BrowserRouter>

通过上面的配置,如果当前路径有匹配到最后一个之外的Route,那么就显示对应内容,不再继续匹配;如果没有匹配到最后一个之外的Route,就显示最后一个Route,因为这个Route可以匹配任何路径。可以把这个Route对应到 404 页面。

3. 匹配到的 Route 如何渲染内容

前面讲述了Route的配置和匹配规则,下面我们讲述一下,当路径匹配到Route之后,会如何渲染对应的内容。

之前有提到过:是在 当前位置 渲染内容,对于一些刚入门的小白来说,可能不能立刻理解当前位置是什么位置。所以我们举个例子,比如我们在项目的App.js组件中有以下配置代码:

class App extends React.Component {
    render() {
        return (
            <div className="content">
                <BrowserRouter>
                    <Route exact path="/" component={Index} />       {/* 位置 A */}
                    <Route path="/help" component={Help} />          {/* 位置 B */}
                    <Route path="/set" component={Set} />            {/* 位置 C */}
                </BrowserRouter>
            </div>
        );
    }
}

那么当路径为 "help" 的时候,就会匹配到第二个Route,那么React Router就会在 位置B 对应的这一行将 Route 组件替换成Help组件;而其他没有匹配到的Route,会被替换成null,相当于将这些 Route 组件直接删去。最终的结果如以下代码所示:

// Help 组件的定义代码可以在上文中找到
class App extends React.Component {
    render() {
        return (
            <div className="content">
                <div className="help-box">
                    帮助与反馈 - 页面
                </div>
            </div>
        );
    }
}

之所以讲这么一个知识点,是为后面介绍如何配置嵌套路由做准备,这里可以先提一下:如果我们想在 组件A中 嵌套几个子路由,那么就可以将这几个Route配置,写到组件A中,一旦路径匹配到了这些Route,就会在组件A中对应的位置渲染子路由对应的组件。听不懂没关系,后面会有详细的解释。

4. 对 React Router 的一点解释

通过上面的笔记,你可能会认为:Route组件必须位于BrowserRouter组件中,且两个组件必须在同一个文件中。

其实不然,从代码结构上说,Route组件确实必须位于BrowserRouter组件中,但是两个组件不一定非要在一个文件中,只要打包编译之后,两个组件满足Route组件位于BrowserRouter组件中就可以。比如以下的写法也是完全正确的:

// 项目的入口文件 index.js
import React from 'react'
import { render } from 'react-dom'
import App from './App'
import { BrowserRouter } from 'react-router-dom'

render((
   <BrowserRouter>
      <App />
   </BrowserRouter>
), document.getElementById('root'))
// App.js 文件
import React from 'react';
import { Route, NavLink } from 'react-router-dom'
import Set from './views/set/Set'
import Help from './views/help/Help'
import Index from './views/index/Index'
import Wallet from './views/wallet/Wallet'

class App extends React.Component {
    render() {
        return (
            {/* 注意这里已经没有了 BrowserRouter 组件  */}
            <div className="content">
                <ul>
                    <NavLink activeClassName="selected" to="help">help</NavLink >
                    <NavLink activeClassName="selected" to="index">index</NavLink >
                    <NavLink activeClassName="selected" to="wallet">wallet</NavLink >
                    <NavLink activeClassName="selected" to="set">set</NavLink >
                </ul>

                <Route path="/help" component={Help} />
                <Route path="/index" component={Index} />
                <Route path="/wallet" component={Wallet} />
                <Route path="/set" component={Set} />
            </div>
        );
    }
}

export default App;

5. 如何配置嵌套路由

嵌套路由,顾名思义就是在一个主路由匹配到的页面中再配置一些路由,我们现在就来讲述以下如何使用 React Router 配置嵌套路由,配置完成之后,我们会看到以下效果:

在之前的基础之上,我们已经配置好了一级路由,即可以通关点击 set 按钮跳转到匹配到的Route对应的组件中,即Set组件,具体配置可以参考上一个代码块中的代码。

下面我们要做的就是在Set组件中,进行配置二级路由,即嵌套路由。配置非常简单,这里先直接给出代码:

import React, { Component } from 'react'
import { Route, Link } from 'react-router-dom'
import SetSystem from '../SetSystem'
import SetPerson from '../SetPerson'
import SetTime from '../SetTime'
import './Set.scss'

class Set extends Component {
    componentDidMount() {
        // 当前页面匹配到的路径,这里是"/set"
        // 使用这个路径,配置Route和Link
        console.log(this.props.match.path);
    }

    render() {
        return (
            <div className="set-box">
                个人设置 - 页面

                <div className="link-list">
                    <Link to={`${this.props.match.path}/system`}>system</Link>
                    <Link to={`${this.props.match.path}/person`}>person</Link>
                    <Link to={`${this.props.match.path}/time`}>time</Link>
                </div>

                <div className="child-router">
                    <Route path={`${this.props.match.path}/system`} component={SetSystem} />
                    <Route path={`${this.props.match.path}/person`} component={SetPerson} />
                    <Route path={`${this.props.match.path}/time`} component={SetTime} />
                </div>
            </div>
        );
    }
}

export default Set;

注意代码中我们引入了 Set.scss 样式文件,给页面元素添加一些非常简单的样式,具体样式你可以自定义,这里的示例代码如下:

.set-box {
    .link-list {
        a {
            margin: 0px 10px;
        }
    }
}

代码书写完成之后,我们就配置好了嵌套路由,启动项目你就可以看到上面GIF中展示的效果。这里对上面的配置做简单的解释:

首先再提一下:匹配到的Route会在 当前位置 渲染匹配到的内容(这个内容可能是component组件,render函数返回的结果等)。

就是因为React Router的这个特性,我们才能配置嵌套路由,否则,及时匹配到了Route,但是我们不知道它的渲染位置,也不能实现此功能。

其次再说一下 this.props.match 这个属性,通过这个属性,我们可以获得当前页面,即一级路由匹配到的组件对应的路径,在这里 this.props.match 的值是 "/set"。

了解了这一点,我们就可以在 this.props.match 的帮助下,设置二级路由的路径。所以以下两种写法是等价的,但是第一种写法更加灵活:

{/* 第一种写法 */}
<Link to={`${this.props.match.path}/system`}>system</Link>
<Route path={`${this.props.match.path}/system`} component={SetSystem} />

{/* 第二种写法 */}
<Link to="/set/system">system</Link>
<Route path="/set/system" component={SetSystem} />

最后再再说一下 Route组件BrowserRouter组件 的位置问题。初次接触React Router的小白可能会问:在设置嵌套路由的时候,Route组件怎么没有包含在BrowserRouter组件中?

事实上,在使用webpack将代码打包打包编译之后,Route组件已经包含在BrowserRouter组件中了。在代码层面我们可以这样理解:Route组件包含于Set组件中,Set组件包含于App组件中,App组件包含在BrowserRouter中。所以Route组件已经包含在BrowserRouter组件中。

四、写在最后

啰啰嗦嗦写完了对React Router的总结,内容挺多但是都很基础,希望可以帮到刚刚入门的小白。

如果大神们看到错误之处,还希望各位能及时指正。