【React Router】React Router学习笔记

React Router学习笔记

  • React Router
    • 1.什么是React Router?
    • 2.为什么要用React Router?
    • 3.基础
      • 3.1 路由配置
      • 3.2 路由匹配原理
      • 3.3 History
        • 3.3.1 browerHistory
        • 3.3.2 hashHistory
        • 3.3.3 createMemoryHistory
        • 3.3.4 实现示例
      • 3.4 默认路由(IndexRoute)与IndexLink
        • 3.4.1 IndexRoute
        • 3.4.2 IndexLink
    • 4.高级用法
      • 4.1 动态路由
      • 4.2 跳转前确认
      • 4.3 服务端渲染
      • 4.4 组件生命周期
      • 4.5 组件外部跳转

React Router

在这里插入图片描述

1.什么是React Router?

React Router 是一个基于 React 之上的强大路由库,它可以让你向应用中快速地添加视图和数据流,同时保持页面与 URL 间的同步。

2.为什么要用React Router?

  1. React Router 知道如何为我们搭建嵌套的 UI,因此我们不用手动找出需要渲染哪些 <Child> 组件。
  2. 获取URL参数。当渲染组件时,React Router 会自动向 Route 组件中注入一些有用的信息,尤其是路径中动态部分的参数。

3.基础

3.1 路由配置

路由配置是一组指令,用来告诉 router 如何匹配 URL以及匹配后如何执行代码。

示例:

import React from 'react'
import { Router, Route, Link } from 'react-router'const App = React.createClass({render() {return (<div><h1>App</h1><ul><li><Link to="/about">About</Link></li><li><Link to="/inbox">Inbox</Link></li></ul>{this.props.children}</div>)}
})const About = React.createClass({render() {return <h3>About</h3>}
})const Inbox = React.createClass({render() {return (<div><h2>Inbox</h2>{this.props.children || "Welcome to your Inbox"}</div>)}
})const Message = React.createClass({render() {return <h3>Message {this.props.params.id}</h3>}
})React.render((<Router><Route path="/" component={App}><Route path="about" component={About} /><Route path="inbox" component={Inbox}><Route path="messages/:id" component={Message} /></Route></Route></Router>
), document.body)

可以使用IndexRoute给路径/添加默认首页

import { IndexRoute } from 'react-router'const Dashboard = React.createClass({render() {return <div>Welcome to the app!</div>}
})React.render((<Router><Route path="/" component={App}>{/* 当 url 为/时渲染 Dashboard */}<IndexRoute component={Dashboard} /><Route path="about" component={About} /><Route path="inbox" component={Inbox}><Route path="messages/:id" component={Message} /></Route></Route></Router>
), document.body)

现在,Apprender 中的 this.props.children 将会是 <Dashboard>这个元素。

现在的sitemap如下所示:

URL组件
/App -> Dashboard
/aboutApp -> About
/inboxApp -> Inbox
/inbox/messages/:idApp -> Inbox -> Message

绝对路径可以将 /inbox/inbox/messages/:id 中去除,并且还能够让 Message 嵌套在 App -> Inbox 中渲染。

React.render((<Router><Route path="/" component={App}><IndexRoute component={Dashboard} /><Route path="about" component={About} /><Route path="inbox" component={Inbox}>{/* 使用 /messages/:id 替换 messages/:id */}<Route path="/messages/:id" component={Message} /></Route></Route></Router>
), document.body)

在多层嵌套路由中使用绝对路径使我们无需在 URL 中添加更多的层级,从而可以使用更简洁的 URL。

绝对路径可能在动态路由中无法使用。

上面的修改使得URL发生了改变,我们可以使用Redirect来兼容旧的URL。

import { Redirect } from 'react-router'React.render((<Router><Route path="/" component={App}><IndexRoute component={Dashboard} /><Route path="about" component={About} /><Route path="inbox" component={Inbox}><Route path="/messages/:id" component={Message} />{/* 跳转 /inbox/messages/:id 到 /messages/:id */}<Redirect from="messages/:id" to="/messages/:id" /></Route></Route></Router>
), document.body)

3.2 路由匹配原理

路由拥有三个属性来决定是否“匹配“一个 URL:

  1. 嵌套关系

    嵌套路由被描述成一种树形结构。React Router 会深度优先遍历整个路由配置来寻找一个与给定的 URL 相匹配的路由。

  2. 路径语法

    :paramName – 匹配一段位于 /?# 之后的 URL。 命中的部分将被作为一个参数
    () – 在它内部的内容被认为是可选的

    *– 匹配任意字符(非贪婪的)直到命中下一个字符或者整个 URL 的末尾,并创建一个 splat 参数

    <Route path="/hello/:name">         // 匹配 /hello/michael 和 /hello/ryan
    <Route path="/hello(/:name)">       // 匹配 /hello, /hello/michael 和 /hello/ryan
    <Route path="/files/*.*">           // 匹配 /files/hello.jpg 和 /files/path/to/hello.jpg
    

    如果一个路由使用了相对路径,那么完整的路径将由它的所有祖先节点的路径和自身指定的相对路径拼接而成。使用绝对路径可以使路由匹配行为忽略嵌套关系。

  3. 优先级

    路由算法会根据定义的顺序自顶向下匹配路由。因此,当拥有两个兄弟路由节点配置时,必须确认前一个路由不会匹配后一个路由中的路径。例如:

    <Route path="/comments" ... />
    <Redirect from="/comments" ... />
    

3.3 History

一个 history 知道如何去监听浏览器地址栏的变化, 并解析这个 URL 转化为 location 对象, 然后 router 使用它匹配到路由,最后正确地渲染对应的组件。

常用的 history 有三种形式, 但也可以使用 React Router 实现自定义的 history

  • browserHistory
  • hashHistory
  • createMemoryHistory
3.3.1 browerHistory

Browser history 是使用 React Router 的应用推荐的 history。它使用浏览器中的 History API 用于处理 URL,创建一个像example.com/some/path这样真实的 URL 。

3.3.2 hashHistory

Hash history 使用 URL 中的 hash(#)部分去创建形如 example.com/#/some/path 的路由。

3.3.3 createMemoryHistory

Memory history 不会在地址栏被操作或读取。同时它也非常适合测试和其他的渲染环境(像 React Native )。这种history需要创建。

const history = createMemoryHistory(location)
3.3.4 实现示例
import React from 'react'
import { render } from 'react-dom'
import { browserHistory, Router, Route, IndexRoute } from 'react-router'import App from '../components/App'
import Home from '../components/Home'
import About from '../components/About'
import Features from '../components/Features'render(<Router history={browserHistory}><Route path='/' component={App}><IndexRoute component={Home} /><Route path='about' component={About} /><Route path='features' component={Features} /></Route></Router>,document.getElementById('app')
)

3.4 默认路由(IndexRoute)与IndexLink

3.4.1 IndexRoute

当用户访问 / 时, App 组件被渲染,但组件内的子元素却没有, App 内部的 this.props.children 为 undefined 。Home 无法参与到比如 onEnter hook 这些路由机制中来。 在 Home 的位置,渲染的是 AccountsStatements。 router 允许使用 IndexRoute ,以使 Home 作为最高层级的路由出现。

<Router><Route path="/" component={App}><IndexRoute component={Home}/><Route path="accounts" component={Accounts}/><Route path="statements" component={Statements}/></Route>
</Router>

现在 App 能够渲染 {this.props.children} 了, 也有了一个最高层级的路由,使 Home 可以参与进来。

3.4.2 IndexLink

如果需要在 Home 路由被渲染后才激活的指向 / 的链接,请使用 <IndexLink to="/">Home</IndexLink>

4.高级用法

4.1 动态路由

React Router 里的路径匹配以及组件加载都是异步完成的,不仅允许延迟加载组件,并且可以延迟加载路由配置。

React Router 会逐渐的匹配 URL 并只加载该 URL 对应页面所需的路径配置和组件。

结合Webpack可以在路由发生改变时,资源按需加载。

const CourseRoute = {path: 'course/:courseId',getChildRoutes(location, callback) {require.ensure([], function (require) {callback(null, [require('./routes/Announcements'),require('./routes/Assignments'),require('./routes/Grades'),])})},getIndexRoute(location, callback) {require.ensure([], function (require) {callback(null, require('./components/Index'))})},getComponents(location, callback) {require.ensure([], function (require) {callback(null, require('./components/Course'))})}
}

4.2 跳转前确认

React Router 提供一个 routerWillLeave 生命周期钩子,这使得 React 组件可以拦截正在发生的跳转,或在离开 route 前提示用户。routerWillLeave 返回值有以下两种:

  1. return false 取消此次跳转
  2. return 返回提示信息,在离开 route 前提示用户进行确认。

可以在 route 组件 中引入 Lifecycle mixin 来安装这个钩子。

import { Lifecycle } from 'react-router'const Home = React.createClass({// 假设 Home 是一个 route 组件,它可能会使用// Lifecycle mixin 去获得一个 routerWillLeave 方法。mixins: [ Lifecycle ],routerWillLeave(nextLocation) {if (!this.state.isSaved)return 'Your work is not saved! Are you sure you want to leave?'},// ...})

推荐使用 React.createClass 来创建组件,初始化路由的生命周期钩子函数。

如果想在一个深层嵌套的组件中使用 routerWillLeave 钩子,只需在 route 组件 中引入 RouteContext mixin,这样就会把 route 放到 context 中。

import { Lifecycle, RouteContext } from 'react-router'const Home = React.createClass({// route 会被放到 Home 和它子组件及孙子组件的 context 中,// 这样在层级树中 Home 及其所有子组件都可以拿到 route。mixins: [ RouteContext ],render() {return <NestedForm />}})const NestedForm = React.createClass({// 后代组件使用 Lifecycle mixin 获得// 一个 routerWillLeave 的方法。mixins: [ Lifecycle ],routerWillLeave(nextLocation) {if (!this.state.isSaved)return 'Your work is not saved! Are you sure you want to leave?'},// ...})

4.3 服务端渲染

服务端渲染与客户端渲染有些许不同,因为你需要:

  • 发生错误时发送一个 500 的响应

  • 需要重定向时发送一个 30x 的响应

  • 在渲染之前获得数据 (用 router 完成这点)

为了迎合这一需求,要在 API 下一层使用:

  • 使用 match 在渲染之前根据location 匹配 route
  • 使用 RoutingContext 同步渲染 route 组件
import { renderToString } from 'react-dom/server'
import { match, RoutingContext } from 'react-router'
import routes from './routes'serve((req, res) => {// 注意!这里的 req.url 应该是从初始请求中获得的// 完整的 URL 路径,包括查询字符串。match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {if (error) {res.send(500, error.message)} else if (redirectLocation) {res.redirect(302, redirectLocation.pathname + redirectLocation.search)} else if (renderProps) {res.send(200, renderToString(<RoutingContext {...renderProps} />))} else {res.send(404, 'Not found')}})
})

4.4 组件生命周期

假如路由配置如下:

<Route path="/" component={App}><IndexRoute component={Home}/><Route path="invoices/:invoiceId" component={Invoice}/><Route path="accounts/:accountId" component={Account}/>
</Route>

路由切换时,组件生命周期的变化情况如下:

  1. 当用户打开应用的/页面

    组件生命周期
    AppcomponentDidMount
    HomecomponentDidMount
    InvoiceN/A
    AccountN/A
  2. 当用户从/跳转到/invoice/123

    组件生命周期
    AppcomponentWillReceiveProps,componentDidUpdate
    HomecomponentWillUnmount
    InvoicecomponentDidMount
    AccountN/A
    • App 从 router 中接收到新的 props(例如 childrenparamslocation 等数据), 所以 App 触发了 componentWillReceivePropscomponentDidUpdate 两个生命周期方法
    • Home 不再被渲染,所以它将被移除
    • Invoice 首次被挂载
  3. 当用户从/invoice/123跳转到/invoice/789

    组件生命周期
    AppcomponentWillReceiveProps,componentDidUpdate
    HomeN/A
    InvoicecomponentWillReceiveProps,componentDidUpdate
    AccountN/A

    所有的组件之前都已经被挂载, 所以只是从 router 更新了 props.

  4. 当从/invoice/789跳转到/accounts/123

    组件生命周期
    AppcomponentWillReceiveProps,componentDidUpdate
    HomeN/A
    InvoicecomponentWillUnmount
    AccountcomponentDidMount

虽然还有其他通过 router 获取数据的方法, 但是最简单的方法是通过组件生命周期 Hook 来实现。示例如下,在 Invoice 组件里实现一个简单的数据获取功能。

let Invoice = React.createClass({getInitialState () {return {invoice: null}},componentDidMount () {// 上面的步骤2,在此初始化数据this.fetchInvoice()},componentDidUpdate (prevProps) {// 上面步骤3,通过参数更新数据let oldId = prevProps.params.invoiceIdlet newId = this.props.params.invoiceIdif (newId !== oldId)this.fetchInvoice()},componentWillUnmount () {// 上面步骤四,在组件移除前忽略正在进行中的请求this.ignoreLastFetch = true},fetchInvoice () {let url = `/api/invoices/${this.props.params.invoiceId}`this.request = fetch(url, (err, data) => {if (!this.ignoreLastFetch)this.setState({ invoice: data.invoice })})},render () {return <InvoiceView invoice={this.state.invoice} />}
})

4.5 组件外部跳转

虽然在组件内部可以使用 this.context.router 来实现导航,但许多应用想要在组件外部使用导航。使用Router组件上被赋予的history可以在组件外部实现导航。

// your main file that renders a Router
import { Router, browserHistory } from 'react-router'
import routes from './app/routes'
render(<Router history={browserHistory} routes={routes}/>, el)
// somewhere like a redux/flux action file:
import { browserHistory } from 'react-router'
browserHistory.push('/some/path')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/116540.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

爬虫爬取数据时怎么配置代理IP来精准导航分析大数据?

在这个数字盛宴中&#xff0c;每一刹那都充满了无数的信息流转。就像瀑布中的水滴&#xff0c;每一滴都承载着可能性。爬虫代理IP与穿云API就像是这场盛宴中的精准导航仪&#xff0c;帮助我们捕捉那些最有价值的信息滴点&#xff0c;确保在这个时代的快速迭代中&#xff0c;我们…

【C++项目】高并发内存池第二讲中心缓存CentralCache框架+核心实现

CentralCache 1.框架介绍2.核心功能3.核心函数实现介绍3.1SpanSpanList介绍3.2CentralCache.h3.3CentralCache.cpp3.4TreadCache申请内存函数介绍3.5慢反馈算法 1.框架介绍 回顾一下ThreadCache的设计&#xff1a; 如图所示&#xff0c;ThreadCache设计是一个哈希桶结构&…

软件测开记录(四)

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

【剑指Offer】37.序列化二叉树

题目 请实现两个函数&#xff0c;分别用来序列化和反序列化二叉树&#xff0c;不对序列化之后的字符串进行约束&#xff0c;但要求能够根据序列化之后的字符串重新构造出一棵与原二叉树相同的树。 二叉树的序列化(Serialize)是指&#xff1a;把一棵二叉树按照某种遍历方式的结…

v-on 可以监听多个方法吗?

目录 ​编辑 前言&#xff1a;Vue 3 中的 v-on 指令 详解&#xff1a;v-on 指令的基本概念 用法&#xff1a;v-on 指令监听多个方法 解析&#xff1a;v-on 指令的优势和局限性 优势 局限性 **v-on 指令的最佳实践** - **适度监听**&#xff1a; - **方法抽离**&#x…

OpenGL —— 2.9、摄像机之模拟CS鼠标视角转动(附源码,glfw+glad)

源码效果 C源码 纹理图片 需下载stb_image.h这个解码图片的库&#xff0c;该库只有一个头文件。 具体代码&#xff1a; vertexShader.glsl #version 330 corelayout(location 0) in vec3 aPos; layout(location 1) in vec2 aUV;out vec2 outUV;uniform mat4 _modelMatrix; …

Kubernetes技术与架构-Ingress Controller

Ingress Controller控制器是实现Ingress对象的定义的组件&#xff0c;也即网关&#xff0c;负责Kubernetes集群内流量的分发&#xff0c;Kubernetes可以运行多个Ingress Controller控制器实例&#xff0c;不同的Ingress定义可以使用不同的Ingress Controller控制器实现&#xf…

JVM工具使用(jstat + jmap)

命令格式 jstat -gcutil pid interval(ms) 举例&#xff1a; jstat -gcutil 16361 1000 线上服务器的GC情况如下&#xff1a; 参数说明如下&#xff1a; S0: 新生代中Survivor space 0区已使用空间的百分比S1: 新生代中Survivor space 1区已使用空间的百分比E: 新生代已使用空…

查看当前cmake版本支持哪些版本的Visual Studio

不同版本的的cmake对Visual Studio的版本支持不同&#xff0c;以下图示展示了如何查看当前安装的cmake支持哪些版本的Visual Studio。 1.打开cmake-gui 2.查看cmake支持哪些版本的Visual Studio

Unity读取写入Excel

1.在Plugins中放入dll&#xff0c;118开头的dll在Unity安装目录下&#xff08;C:\Program Files\Unity\Editor\Data\Mono\lib\mono\unity&#xff09; 2.写Excel public void WriteExcel(){//文件地址FileInfo newFile new FileInfo(Application.dataPath "/test.xlsx…

无障碍阅读他人开源项目结构:看完本文,你将信心满满

先看看阿里是怎么约定的 我印象中&#xff0c;以前在看《阿里巴巴Java开发手册》时&#xff0c;好像有关于工程结构和应用分层相关的内容&#xff0c;于是我回翻了一下&#xff0c;果然有&#xff1a; 它这里面讲的内容大概就是&#xff1a;关于一个正常的企业项目里一种通用的…

一款功能强大的音乐曲谱软件Guitar Pro 8 .1.1for Mac 中文破解版

Guitar Pro 8 .1.1for Mac 中文破解版是一款功能强大的音乐曲谱软件&#xff0c;非常适合学习如何玩&#xff0c;改进技巧&#xff0c;重现喜爱的歌曲或陪伴自己。可以帮助我们进行吉他的学习、绘谱与创作&#xff0c;它包含了几乎所有的吉他现有指法及音色&#xff0c;在做弹拨…

黄金现货操作与盈亏

现在作黄金现货买卖&#xff0c;投资者已经完全以电子化的方式来进行&#xff0c;国内和香港的投资者&#xff0c;通过香港的正规平台入市&#xff0c;可以获得50倍的资金杠杆&#xff0c;以及全天候交易的机会&#xff0c;只要掌握了一些基本的操作方式&#xff0c;所有投资者…

buuctf[极客大挑战 2019]Havefun 1

网页环境title标题每一帧都不要放过&#xff0c;或许那个不起眼的地方就存在重要信息到这并未发现什么重要信息&#xff0c;F12看看在源代码底部发现PHP代码&#xff1a; <!-- $cat$_GET[cat]; echo $cat; if($catdog){ echo Syc{cat_cat_cat_cat}; } --> PHP代码…

3D测量之圆孔测量 拟合圆 点云变换

0. 效果展示 1. 圆孔测量介绍 此文中的圆孔测量是一项3D视觉技术,旨在精确测量物体表面上的圆孔的直径和中心坐标。通过使用高精度3D相机(线激光轮廓仪或结构体等)采集原始点云数据,通过3D视觉算法能够快速、准确地分析物体上的圆孔特征,为制造和工程领域提供了强大的测量…

STM32+摁键与定时器实现Led灯控制(中断)

中断作为单片机开发必须掌握的内容&#xff0c;它能够在不搭载操作系统的情况下让我们体验多任务处理的快感&#xff0c;保证了高优先级任务的实时性&#xff0c;同时系统中断也能够提供给用户在核心发生错误之后进行处理的机会。STM32F103系列单片机中断非常强大&#xff0c;每…

GaussDB数据库管理系统介绍

1.GaussDB的发展 2.GaussDB的生态 内部&#xff1a; 云化自动化方案。通过数据库运行基础设施的云化将DBA(数据库管理员)和运维人员的日常工作 自动化。外部&#xff1a; 采用与数据库周边生态伙伴对接与认证的生态连接融合方案&#xff0c;解决开发者/DBA难获取、应用难对接等…

VR虚拟展厅的亮点是什么?有哪些应用?

传统展厅主要是以静态陈列的形式来传达内容&#xff0c;而展示形式则有图片、视频等&#xff0c;虽然视频包含内容多&#xff0c;但是总体具有一定的局限性&#xff0c;客户体验感也较差&#xff0c;往往不能深入了解细节。随着VR技术越来越成熟&#xff0c;VR技术的广泛应用&a…

【谢希尔 计算机网络】第4章 网络层

目录 网络层 网络层的几个重要概念 网络层提供的两种服务 网络层的两个层面 网际协议 IP 虚拟互连网络 IP 地址 IP 地址与 MAC 地址 地址解析协议 ARP IP 数据报的格式 IP 层转发分组的过程 基于终点的转发 最长前缀匹配 使用二叉线索查找转发 网际控制报文协议…

2023年中国互联网视听平台发展趋势分析:未来增速将从2023年开始缓慢提升[图]

互联网视听平台是指基于互联网技术&#xff0c;提供包括音频、影视、综艺节目、直播、短视频等内容的数字化传播平台。互联网视听平台通过电脑端、移动端等多种终端提供在线点播、直播、互动等服务&#xff0c;具有内容丰富、便捷高效、交互性强等特点&#xff0c;是大众获取娱…