【AICon】探索RAG 技术在实际应用中遇到的挑战及应对策略!AICon精华内容已上线73%>>> 了解详情
写点什么

深入理解 React(二) - 数据流和事件原理

  • 2019-08-21
  • 本文字数:4278 字

    阅读完需:约 14 分钟

深入理解React(二) - 数据流和事件原理


这个,叫做竹笕,是中日传统禅文化中常见的庭院装饰品,它的构造可简单可复杂,但原理很简单,比如这个竹笕,水从竹笕顶部入口流入内部,并按照固定的顺序从上向下依次流入各个小竹筒,然后驱动水轮转动。对于强迫症患者来说,观赏竹笕的绝对是一种很享受的过程的最爱,你会发现这些小玩意竟然能这么流畅的协调起来,好神奇。



如果竹笕是一个组件的话,那么水就是组件的数据流。


在 React 中,数据流是自上而下单向的从父节点传递到子节点,所以组件是简单且容易把握的,他们只需要从父节点提供的 props 中获取数据并渲染即可。如果顶层组件的某个 prop 改变了,React 会递归地向下遍历整棵组件数,重新渲染所有使用这个属性的组件。




这个是前面看到的 KM 热点问题组件,拥有一个叫做 articles 的属性。


在组件内部,可以通过 this.props 来访问 props,props 是组件唯一的数据来源,对于组件来说:


props 永远是只读的。


不要尝试在组件内部调用 setProps 方法来修改 props,如果你不小心这么做了,React 会报错并给出非常详细的错误提示。


组件的属性类型如果不进行声明和验证,那么很可能使用者传给你的属性值或者类型是无效的,那会导致一些意料之外的故障。好在 React 已经为我们提供了一套非常简单好用的属性校验机制——



React 有一个 PropTypes 属性校验工具,经过简单的配置即可。当使用者传入的参数不满足校验规则时,React 会给出非常详细的警告,定位问题不要太容易。



PropTypes 包含的校验类型包括基本类型、数组、对象、实例、枚举——



以及对象类型的深入验证等等。如果内置的验证类型不满足需求,还可以通过自定义规则来验证。


如果某个属性是必须的,在类型后面加上 isRequired 就可以了。



React 的一大创新,就是把每一个组件都看成是一个状态机,组件内部通过 state 来维护组件状态的变化,这也是 state 唯一的作用。



state 一般和事件一起使用,我们先看 state,然后看看 state 和事件怎样结合。


这是一个简单的开关组件,开关状态会以文字的形式表现在按钮的文本上。


首先看 render 方法,返回了一个 button 元素,给 button 注册了一个事件用来处理点击事件,在点击事件中对 state 的 on 字段取反,并执行 this.setState() 方法设置 on 字段的新值。一个开关组件就完成了。



组件渲染完成后,必须有 UI 事件的支持才能正常工作。



React 通过将事件处理器绑定到组件上来处理事件。


React 事件本质上和原生 JS 一样,鼠标事件用来处理点击操作,表单事件用于表单元素变化等,Rreact 事件的命名、行为和原生 JS 差不多,不一样的地方是 React 事件名区分大小写。


比如这段代码中,Article 组件的 section 节点注册了一个 onClick 事件,点击后弹出 alert。


有时候,事件的处理器需要由组件的使用者来提供,这时可以通过 props 将事件处理器传进来。



这个是刚才那个 Article 组件的使用者,它提供给 Article 组件的 props 中包含了一个 onClick 属性,这个 onClick 指向这个组件自身的一个事件处理器,这样就实现了在组件外部处理事件回调。



这是一个 React 组件实现组件可交互所需的流程,render()输出虚拟 DOM,虚拟 DOM 转为 DOM,再在 DOM 上注册事件,事件触发 setState()修改数据,在每次调用 setState 方法时,React 会自动执行 render 方法来更新虚拟 DOM,如果组件已经被渲染,那么还会更新到 DOM 中去。



这些是 React 目前支持的事件列表。



React 的组件拥有一套清晰完整而且非常容易理解的生命周期机制,大体可以分为三个过程:初始化、更新和销毁,在组件生命周期中,随着组件的 props 或者 state 发生改变,它的虚拟 DOM 和 DOM 表现也将有相应的变化。



首先是初始化过程,这里会着重讲,需要充分理解。


组件类在声明时,会先调用 getDefaultProps() 方法来获取默认 props 值,这个方法会且只会在声明组件类时调用一次,这一点需要注意,它返回的默认 props 由所有实例共享。


在组件被实例化之前,会先调用一次实例方法 getInitialState() 方法,用于获取这个组件的初始 state。


实例化之后就是渲染,componentWillMount 方法会在生成虚拟 DOM 之前被调用,你可以在这里对组件的渲染做一些准备工作,比如计算目标容器尺寸然后修改组件自身的尺寸以适应目标容器等等。


接下来就是渲染工作,在这里你会创建一个虚拟 DOM 用来表示组件的结构。对于一个组件来说,render 是唯一一个必须的方法。


render 方法需要满足这几点:

1.只能通过 this.props 或 this.state 访问数据

2.只能出现一个顶级组件

3.可以返回 null、false 或任何 React 组件

4.不能对 props、state 或 DOM 进行修改

需要注意的是,render 方法返回的是虚拟 DOM。


渲染完成以后,我们可能需要对 DOM 做一些操作,比如截屏、上报日志、或者初始化 iScroll 等第三方非 React 插件,可以在 componentDidMount() 方法中做这些事情。当然,你也可以在这个方法里通过 this.getDOMNode() 方法取得最终生成 DOM 节点,然后对 DOM 节点做爱做的事情,但需要注意做好安全措施,不要缓存已经生成的 DOM 节点,因为这些 DOM 节点随时可能被替换掉,所以应该在每次用的时候去读取。


组件被初始化完成后,它的状态会随着用户的操作、时间的推移、数据更新而产生变化,变化的过程是组件声明周期的另一部分 ——



更新过程。


当组件已经被实例化后,使用者调用 setProps() 方法修改组件的数据时,组件的 componentWillReceiveProps() 方法会被调用,在这里,你可以对外部传入的数据进行一些预处理,比如从 props 中读取数据写入 state。


默认情况下,使用者调用组件的 setProps() 方法后,React 会遍历这个组件的所有子组件,进行“灌水”,将 props 从上到下一层一层传下去,并逐个执行更新操作,虽然 React 内部已经进行过很多的优化,这个过程并不会花费多少时间,但是程序员里永远不缺乏长期性能饥渴的同学,不用担心,React 有一个能够解决你性能饥渴的办法——shouldComponentUpdate()。


有时候,props 发生了变化,但组件和子组件并不会因为这个 props 的变化而发生变化,打个比方,你有一个表单组件,你想要修改表单的 name,同时你能够确信这个 name 不会对组件的渲染产生任何影响,那么你可以直接在这个方法里 return false 来终止后续行为。这样就能够避免无效的虚拟 DOM 对比了,对性能会有明显提升。


如果这个时候有同学仍然饥渴难耐,那么你可以尝试 不可变数据结构(用过 mongodb 的同学应该懂)。


组件在更新前,React 会执行 componentWillUpdate() 方法,这个方法类似于前面看到的 componentWillMount()方法,唯一不同的地方只是这个方法在执行的时候组件是已经渲染过的。需要注意的是,不可以在这个方法中修改 props 或 state,如果要修改,应当在 componentWillReceiveProps() 中修改。


然后是渲染,React 会拿这次返回的虚拟 DOM 和缓存中的虚拟 DOM 进行对比,找出【最小修改点】,然后替换。


更新完成后,React 会调用组件的 componentDidUpdate 方法,这个方法类似于前面 componentDidMount 方法,你仍然可以在这里可以通过 this.getDOMNode() 方法取得最终的 DOM 节点。


香港电影结尾经常看到一个剧情,就是英雄打败了坏人,然后警察出来擦屁股——



警察偶尔还能立功,而 componentWillUnmount 最可怜,他除了擦屁股什么也做不了。


你可以在这个方法中销毁非 React 组件注册的事件、插入的节点,或者一些定时器之类。这个过程可能容易出错,比如绑定了事件却没销毁,这个 React 可帮不了你。



两节内容讲了上手 React 所必备的知识。后面讲价值。



直出有多快我就不多说了。因为有虚拟 DOM 的存在,React 可以很容易的将虚拟 DOM 转换为字符串,这便使我们可以只写一份 UI 代码,同时运行在 node 里和和浏览器里。



在 node 里将组件 HTML 渲染为一段 HTML 一句话即可。不过围绕这个 renderToString 我们还要做一些准备工作。代码有点多,大家做好心理准备。



这是一个 express 的路由方法,在这里:


1.从后台 server 或数据库等来源拉取数据


2.引入要渲染的 React 组件


3.调用 React.renderToString()方法来生成 HTML


4.最后发送 HTML 和数据给浏览器


这里为了方便描述,没有写拉取数据的代码,大家自行脑补。


需要注意的是这里的 JSON 字符串中可能出现结尾标签或 HTML 注释,可能会导致语法错误,这里需要进行转义。



页面的示例代码本来打算用大家更熟悉的 HTML,但发现代码量太多了 PPT 里一页放不下,所以换成了 jade 代码,没用过 jade 的同学也顺便了解一下,我也顺便给 jade 打个广告。


这个页面做了 X 个事:


1.将前面在 action 里生成的 HTML 写到 #container 元素里


2.引入必须的 JS 文件


3.获取 action 提供的数据


4.渲染组件


这就是 React 的服务端渲染,组件的代码前后端都可以复用。<有没有没理解清楚的同学?>


是不是感觉 React 挺牛逼的?大家以为 React 就这么点能耐吗?




React 能够用一套代码同时运行在浏览器和 node 里,而且能够以原生 App 的姿势运行在 iOS 和 Android 系统中,即拥有了 web 迭代迅速的特性,又拥有原生 App 的体验。


这个姿势叫做 React-Native。


这是 React 和 React-Native 在 github 上的数据,可以看出 React-Native 也是相当热门——因为 React-Native 能够使 React 的价值最大化,这个价值是什么呢——对业务来说,意味着不需要为了做终端版本就招聘和前端等量人力的终端开发,同时意味着我们成为全栈工程师有了一个捷径。



了解 iOS 开发的同学都知道,水果公司对应用上架的审核效率实在让人无力吐槽,很多团队上一个版本还没审核结束,下一个版本就已经做好了。而 React-Native 支持从网络拉取 JS,这样 iOS 应用也能够像 web 一样实现快速迭代了。



这个是 react-native 的调试过程


作为一个没写过一句 Object-C 代码的 web 前端开发,我只用了一天时间就上手了 react-native,然后用了半天时间做出了一个简单的 demo 页面,可以看到 react-native 的生产效率还是非常高的。



单元测试顾名思义,是对各个模块进行最小范围的测试,容易。


我们来演示一个 checkbox 的单元测试过程。



看代码



因为虚拟 DOM 的存在,使得 react 的代码很容易做好单元测试,这是上面那段代码的测试用例,通过 karma 执行后即可看到结果。



所以你可能需要这些东西









课后练习



(如果你已经看到这里了,为何不再花 1 分钟思考一下上面 3 个问题)


作者介绍:


左明,企鹅电竞前端团队 leader,腾讯高级工程师。从事 web 开发超过 8 年,主导过微云 web 版、腾讯云助手、手 Q 游戏公会、企鹅电竞 App 等项目,有丰富的前端架构经验。


本文转载自公众号小时光茶舍(ID:gh_7322a0f167b5)。


原文链接:


https://mp.weixin.qq.com/s/c8fIET_JdZvSKRLl3H6aNQ


2019-08-21 17:063809

评论

发布
暂无评论
发现更多内容

Mac电脑图片处理必备:Photoshop 2021直装激活版

mac大玩家j

Mac软件 图片编辑工具 图片处理软件

群星璀璨!亚信科技、TM Forum联合举办数字领导力中国峰会,助百行千业打造转型升级双引擎

亚信AntDB数据库

AntDB AntDB数据库

Wireshark中的ARP协议包分析是什么?

小齐写代码

想快速解决数据问题?ETLCloud教你秒上手

RestCloud

ETL 数据集成

即时通讯技术文集(第26期):实时音视频技术合集(Part1) [共16篇]

JackJiang

网络编程 即时通讯 IM

简单解压缩工具Keka 激活最新中文版+使用方法

胖墩儿不胖y

Mac软件 解压缩软件 解压缩工具

云服务器的安全防护:技术与策略全面解析

一只扑棱蛾子

云服务器

亚马逊云科技推出五项Amazon SageMaker新功能

财见

B 站基于 StarRocks 构建大数据元仓

StarRocks

数据库 StarRocks 数据分析、

淘宝/天猫商品详情 API 的技术架构是怎样的?

技术冰糖葫芦

API 开发

WebSocket 连接:完全指南及高效实现方法

Apifox

程序员 前端 Web 网络编程 websocket

AI数字人在抖音开播教程!

青否数字人

数字人

台灣用友×新漢智能出席兩岸企業家峰會,探訪新格局下兩岸資訊產融合發展新機遇

用友BIP

亚马逊云科技携手埃森哲助力默沙东利用云技术缩短药物发现时间

财见

13 | 线性排序:如何根据年龄给100万用户数据排序?

鲁米

centos使用pip安装ansible教程。

百度搜索:蓝易云

Linux centos 运维 pip ansible

图控软件大盘点 国内外顶级SCADA软件整理

2D3D前端可视化开发

组态软件 工业自动化 SCADA HMI 图控软件

用 2 种方法取消 Axios 请求,掌控请求的主动权

Liam

JavaScript 程序员 前端 axios 网络请求

每日一题:LeetCode-78. 子集

半亩房顶

面试 算法 LeetCode 刷题 回溯

centOS7的home目录进行扩容教程。

百度搜索:蓝易云

云计算 Linux centos 运维 云服务器

LED屏幕在指挥中心的解决方案

Dylan

LED显示屏 led显示屏厂家 户内led显示屏

7 种查询策略教你用好 Graph RAG 探索知识图谱

NebulaGraph

知识图谱 LLM rag

可视化软件开发工具——JNPF

互联网工科生

低代码开发 可视化开发 JNPF

公有云频繁宕机,从上云到下云备份如何实现?

财见

12 月 10 日,融云在 Google DevFest 上海站等你!

融云 RongCloud

Google 即时通讯 IM 融云 Google DevFest

技术博客:Vue中各种混淆用法汇总

雪奈椰子

Ulysses for Mac(Markdown文本编辑器) 33.1永久激活版

mac

文本编辑器 苹果mac Windows软件 Ulysses

如何通过营销策略和资源平台提升API竞争力

幂简集成

API 产品运营 营销模式 差异化

Vue 应用程序性能优化:代码压缩、加密和混淆配置详解

什么是微信小程序WXSS ?

Geek_2305a8

细说SQL与ETL之间的小秘密

华为云开发者联盟

数据库 后端 华为云 华为云GaussDB 华为云开发者联盟

深入理解React(二) - 数据流和事件原理_大前端_左明_InfoQ精选文章