react 精华之react-router .HashRouter 还是 BrowserRouter . 动态路由是根据变量决定这个路由是否需要进行

2023-11-12

随着 AJAX 技术的成熟,现在单页应用(Single Page Applicatio)已经是前端网页界的标配,名为“单页”,其实在设计概念上依然是多页的界面,只不过从技术层面上页之间的切换是没有整体网页刷新的,只需要做局部更新。

要实现“单页应用”,一个最要紧的问题就是做好“路由”(Routing),也就是处理好下面两件事:

  1. 把 URL 映射到对应的页面来处理;
  2. 页面之间切换做到只需局部更新。

感谢业界前人给我们开发者铺平了道路,在 React 的世界里,上面说的问题都有成熟解法,其中最热门的工具,就是 react-router,这一节我们就来介绍这个工具。

react router v4 的动态路由

我们现在说到 react-router,基本上都是在说 react-router 的第 4 版,也就是 v4。这个 v4 很有意思,它完全推翻了之前 v3 的做法。可以说,react-router 的 v3 和 v4 版完完全全是不同的两个工具,两者差距实在太大。

其实当初 v3 也已经很优秀很热门了,但是 react-router 的开发者不满意,他们认为 v3 还是落入了“静态路由”的窠臼,所以在 v4 中 react-router 做到了“动态路由”的功能。

所谓“静态路由”,就是说路由规则是固定的,无论 express、Angular 还是 Rails 等业界响当当的框架,都用的是静态路由。以 express 为例,路由规则差不多是这么写的:

app.get('/', Home);
app.get('/product/:id', Product);
app.get('/about', About);

对于大部分应用,支持这样的路由规则真的是足够了,但是,react-router 的开发者觉得这样还不够好,要支持“动态路由”才是最好。

所谓动态路由,指的是路由规则不是预先确定的,而是在渲染过程中确定的。因为 react-router 的定位就是专供 React 应用服务,而 React 的世界中一切皆为组件,所以 react-router v4 就完全用 React 组件来实现路由功能。

不得不承认,虽然 react-router 的开发者是挺折腾的,但是他们的确是领悟了 React 的精髓,而且在 react-router 中把 React 的哲学发挥到了极致。

接下来,我们通过一个很简单的例子来说明 react-router v4 如何工作的,然后在这个例子的基础上介绍“动态路由”。

React Router 实例

安装包 react-router-dom

create-react-app 产生的应用默认为不支持多个页面,但还是在 README 文件中友情推荐了一下 react-router 来增强功能,可见 react-router 影响力之大。

不过,我们并不需要安装 react-router 这个 npm 包,因为 react-router 为了支持 Web 和 React Native 出了两个包—— react-router-dom 和 react-router-native ,我们只关心 Web,所以只需要安装 react-router-dom 。这个 react-router-dom 依赖于 react-router ,所以 react-router 也会被自动安装上。

npm install react-router-dom

HashRouter 还是 BrowserRouter

react-router 的工作方式,是在组件树顶层放一个 Router 组件,然后在组件树中散落着很多 Route 组件(注意比 Router 少一个“r”),顶层的 Router 组件负责分析监听 URL 的变化,在它保护伞之下的 Route 组件可以直接读取这些信息。

很明显,Router 和 Route 的配合,就是之前我们介绍过的“提供者模式”,Router 是“提供者”,Route是“消费者”。

更进一步,Router 其实也是一层抽象,让下面的 Route 无需各种不同 URL 设计的细节,不要以为 URL 就一种设计方法,至少可以分为两种。

第一种很自然,比如 / 对应 Home 页,/about 对应 About 页,但是这样的设计需要服务器端渲染,因为用户可能直接访问任何一个 URL,服务器端必须能对 /的访问返回 HTML,也要对 /about的访问返回 HTML。

第二种看起来不自然,但是实现更简单。只有一个路径 /,通过 URL 后面的 # 部分来决定路由,/#/ 对应 Home 页,/#/about 对应 About 页。因为 URL 中#之后的部分是不会发送给服务器的,所以,无论哪个 URL,最后都是访问服务器的 / 路径,服务器也只需要返回同样一份 HTML 就可以,然后由浏览器端解析 # 后的部分,完成浏览器端渲染。

在 react-router,有 BrowserRouter 支持第一种 URL,有 HashRouter 支持第二种 URL。

因为 create-react-app 产生的应用默认不支持服务器端渲染,为了简单起见,我们在下面的例子中使用 HashRouter,在实际产品中,其实最好还是用 BrowserRouter,这样用户体验更好。

修改index.js文件,增加下面的代码:

import {HashRouter} from 'react-router-dom';

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

把 Router 用在 React 组件树的最顶层,这是最佳实践。因为将来我们如果想把 HashRouter 换成 BrowserRouter,组件 App 以下几乎不用任何改变。

 

使用 Link

对于单页应用,需要在不同“页面”之间切换,往往需要一个“导航栏”,我们在这里也实现一个简单的导航栏。

App.js中,我们让网页由两个组件 Navigation 和 Content 组成, Navigation 就是导航栏,而 Content 是具体内容。

class App extends Component {
  render() {
    return (
      <div className="App">
        <Navigation />
        <Content />
      </div>
    );
  }
}

我们计划只增加两个页面,在 Navigation 中就应该有两个链接,但是,如果我们简单使用 HTML 的 <a> 标签那就错了,用户点击 <a> 标签缺省行为是网页跳转,这违背了“单页应用”的原则。虽然对于 HashRouter 使用的是没有网页跳转的 #,但是为了将来可以无缝切换为 BrowserRouter ,我们也不能使用 <a href="#about"> 这样的标签。

正确的解法是用 react-router 提供的 Link 组件,虽然 Link 最终还是渲染为 <a> 标签,但这是有神力的 <a> 标签,用户点击时,react-router 可以知晓这是一个单页应用的链接,不用网页跳转只做局部页面更新。

const ulStyle = {
  'list-style-type': 'none',
  margin: 0,
  padding: 0,
};

const liStyle = {
  display: 'inline-block',
  width: '60px',
};

const Navigation = () => (
  <header>
    <nav>
      <ul style={ulStyle}>
        <li style={liStyle}><Link to='/'>Home</Link></li>
        <li style={liStyle}><Link to='/about'>About</Link></li>
      </ul>
    </nav>
  </header>
)

使用 Route 和 Switch

我们来看 Content 这个组件,这里会用到 react-router 最常用的两个组件 Route 和 Switch。

const Content = () => (
  <main>
    <Switch>
      <Route exact path='/' component={Home}/>
      <Route path='/about' component={About}/>
    </Switch>
  </main>
)

Route 组件的 path 属性用于匹配路径,因为我们需要匹配 / 到 Home,匹配 /about 到 About,所以肯定需要两个 Route,但是,我们不能这么写。

      <Route path='/' component={Home}/>
      <Route path='/about' component={About}/>

如果按照上面这么写,当访问 /about 页面时,不光匹配 /about,也配中 /,界面上会把 Home 和 About 都渲染出来的。

解决方法,可以在想要精确匹配的 Route 上加一个属性 exact,或者使用 Switch 组件。

可以把 Switch 组件看做是 JavaScript 的 switch 语句,像这样:

switch (条件) {
  case 1: 渲染1; break;
  case 2: 渲染2; break;
}

从上往下找第一个匹配的 Route,匹配中了之后,立刻就 break,不继续这个 Switch 下其他的 Route 匹配了。

可以看到,react-router 巧妙地用 React 组件实现了路由的所有逻辑,印证了那句话:React 世界里一切都是组件。

动态路由

在了解了 react-router的基本路由功能之后,再来理解“动态路由”就容易了。

假设,我们增加一个新的页面叫 Product,对应路径为 /product,但是只有用户登录了之后才显示。如果用静态路由,我们在渲染之前就确定这条路由规则,这样即使用户没有登录,也可以访问 product,我们还不得不在 Product 组件中做用户是否登录的检查。

如果用动态路由,则只需要在代码中的一处涉及这个逻辑:

    <Switch>
      <Route exact path='/' component={Home}/>
      {
        isUserLogin() &&
        <Route exact path='/product' component={Product}/>,
      }  
      <Route path='/about' component={About}/>
    </Switch>

可以用任何条件决定 Route 组件实例是否渲染,比如,可以根据页面宽度、设备类型决定路由规则,动态路由有了最大的自由度。

 

BrowserHistory也不一定非要服务端渲染  配置一下静态服务器的规则就行了,例如nginx的配置: ``` location / { try_files $uri /index.html; }

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

react 精华之react-router .HashRouter 还是 BrowserRouter . 动态路由是根据变量决定这个路由是否需要进行 的相关文章

随机推荐

  • 正点原子imx6ull开发板视频监控项目实战系列1: 总体方案介绍

    前言 本项目借鉴正点原子 韦东山老师 讯为电子和众多大牛的博客的资料 如果有侵权 还请告知 若情况属实 我将第一时间删除道歉 正文 方案1 在局域网内实现视频监控 这种方案 我们需要写两个程序 1 在连接摄像头的ARM板子上 实现一个服务器
  • Ubuntu关闭休眠模式

    There are 3 suspend modes in Linux Suspend to RAM Normal Suspend This is the mode that most laptops automatically enter
  • 【Matlab】基于多元线性的数据回归预测(Excel可直接替换数据)

    Matlab 基于多元线性的数据回归预测 Excel可直接替换数据 1 模型原理 2 模型说明 3 数据说明 4 代码绘图 5 输出回归模型 6 代码及注释 1 模型原理 多元线性回归原理概述如下 多元线性回归是一种对一个因变量和多个自变量
  • 学习若依框架----之----字符串工具类StringUtil

    文章目录 字符串工具类 1 获取参数不为空值 方法名 nvl 2 判断一个Collection是否为空 包含 List Set Queue 方法名 isEmpty 3 判断一个Collection是否非空 包含 List Set Queue
  • Android Studio快捷操作

    要快速查找并运行检查 请按Ctrl Alt Shift I并开始键入检查名称或其组 从建议列表中选择所需的检查 然后指定所需的范围 例如输入unused resources可以检查未使用到的资源 在编辑器中 Ctrl N 搜索类 也可以使用
  • 改变多个ul下第一个li的样式

    body内的代码如下 ul li 华仔 li li 华仔 li li 华仔 li ul ul li 磊磊 li li 磊磊 li li 磊磊 li ul function 方式一 var lis ul for var i 0 i
  • 开发中遇到的问题--java.lang.IllegalStateException

    在实际开发中经常会遇到java lang IllegalStateException的异常 下面是我所遇到的java lang IllegalStateException的解决方法 1 在APP首页的导航栏 一共有五个栏目 要求一页只显示4
  • Jsf与Spring的整合原理

    Jsf做为Web框架 Spring做为业务层框架 两者可以结合起来用 只要在faces config xml中做一个很简单的配置
  • QT日常积累1:QT_BEGIN_NAMESPACE和QT_END_NAMESPACE

    QT BEGIN NAMESPACE class QAbstractButton class QAbstractSlider class QComboBox QT END NAMESPACE 学习QT过程中遇到了上面的问题 不明白是什么意思
  • 线性代数(十九) : 行列式的性质

    首先说明行列式的三个基本性质 然后从基本性质推导出其他性质 1 行列式的基本性质 1 性质一 单位矩阵的行列式的值为1 det I 1 2 性质二 交换矩阵的两行行列式的值的符号改变 det A det B 矩阵B由A交换两行得到 3 性质
  • 数据中台产品【数据服务中心】【含代码说明等】

    链接 https pan baidu com s 1 WNnt690 WWf8BX8uvNaKw 提取码 uscrDataCenterTodo CDH hbase zk 部署和配置 代码发布 presto redis集群 cacheclou
  • Vscode运行C++程序修改代码运行不生效

    修改代码运行不生效 问题描述 问题描述 以以下代码为例 具体问题就是每次修改代码之后运行发现都没有生效 比如第一次编译运行打印了 Hello 我在添加新语句后运行程序发现修改并未生效 网上找解决方法大多是下面这种 点击左下角设置标志图 gt
  • 什么是ajax ?ajax的原理是什么?ajax的优缺点是什么?ajax请求的五个步骤和ajax的基本语法。(简述)

    一 什么是ajax Ajax即Asynchronous Javascript And XML 异步JavaScript和XML ajax不是新的编程语言 而是一种使用现有标准的新方法 ajax是一种在无需重新加载整个网页的情况下 能够更新部
  • 识别视频声音内容添加字幕

    最近有看到这个需求 想着怎么实现一下 做到这个功能主体上也就几步 声音识别生成字幕 识别视频内的声音内容转成字幕文件 这一步有可能需要先将音频从视频中剥离出来 可以用ffmpeg来实现 声音转化成字幕的方法 网上查到可用的方法有以下几种 百
  • vue-架构与思想-MVVM模式和MVC模式的区别

    今天又重新捡起Vue 想用vue做个自己的应用 作为一个后台服务的se 对前台一直是很苦恼的 然后按着这个思路就干起来了 当然就遇到了这个问题 MVVM到底是什么 MVC当然是清楚的 那么找了些资料 学习以记之 与君共享 1 MVVM模式和
  • (二十七)admin-boot项目之集成websocket实时推送消息

    文章目录 二十七 集成websocket实时推送消息 一 rabbitmq推送方案 二 websocket方案 mica mqtt core 三 mica mqtt方案测试 二十七 集成websocket实时推送消息 基础项目地址 http
  • 使用Settings Sync扩展同步VSCode配置

    声明 本文全部内容为原创内容 禁止在未经授权的情况下进行任何二次创作和修改 转载请注明出处 摘要 VSCode是一个广泛使用的开源代码编辑器 因为支持Windows Mac OS X和Linux的多平台的特性而广受欢迎 由于大量扩展的支持
  • 一文读懂使用STM32驱动 LCD1602 液晶显示屏(基于Mbed Studio平台)

    索引 一 总览 1 1 简介 1 2 LCD1602主要参数 二 管脚介绍 三 时序图 3 1 写操作时序 3 2 读操作时序 3 3 时序时间参数 四 命令与数据 以使用4位数据模式为例 4 1 前期准备 4 2 写入命令 命令表 4 3
  • 蓝牙Mesh LPN节点

    选择LPN模式的原因 能有效的降低产品功耗 比如 一个温湿度传感器产品 需要超过设定阈值才会从上送数据 这样就没有长时间唤醒时间 就无法接收到网关下发的设置数据 这时候就需要LPN模式 LPN的节点正常还是超过阈值才会上报数据 然后会过一段
  • react 精华之react-router .HashRouter 还是 BrowserRouter . 动态路由是根据变量决定这个路由是否需要进行

    随着 AJAX 技术的成熟 现在单页应用 Single Page Applicatio 已经是前端网页界的标配 名为 单页 其实在设计概念上依然是多页的界面 只不过从技术层面上页之间的切换是没有整体网页刷新的 只需要做局部更新 要实现 单页