精读《setState 做了什么》
1 引言
setState
是 React 框架最常用的命令,它是用来更新状态的,这也是 React 框架划时代的功能。
但是 setState
函数是 react
包导出的,他们又是如何与 react-dom
react-native
react-art
这些包结合的呢?
通过 how-does-setstate-know-what-to-do 这篇文章,可以解开这个秘密。
2 概述
setState
函数是在 React.Component
组件中调用的,所以最自然的联想是,更新 DOM 的逻辑在 react
包中实现。
但是 react
却可以和 react-dom
react-native
react-art
这些包打配合,甚至与 react-dom/server
配合在服务端运行,那可以肯定 react
包中不含有 DOM 更新逻辑。
所以可以推断,平台相关的 UI 更新逻辑分布在平台相关的包里,react
包只做了代理。
React 引擎不在 react 包里
从 react 0.14 版本之后,引擎代码就从 react 包中抽离了,react 包仅仅做通用接口抽象。
也就是说,react 包定义了标准的状态驱动模型的 API,而 react-dom
react-native
react-art
这些包是在各自平台的具体实现。
各平台具体的渲染引擎实现被称为 reconciler,通过这个链接可以看到 react-dom
react-native
react-art
这三个包的 reconciler 实现。
这说明了 react 包仅告诉你 React 拥有哪些语法,而并不关心如何实现他们,所以我们需要结合 react 包与 react-xxx 一起使用。
对于 context
,react 包仅仅会做如下定义:
// A bit simplified
function createContext(defaultValue) {let context = {_currentValue: defaultValue,Provider: null,Consumer: null};context.Provider = {$$typeof: Symbol.for("react.provider"),_context: context};context.Consumer = {$$typeof: Symbol.for("react.context"),_context: context};return context;
}
具体用到时,由 react-dom
和 react-native
决定用何种方式实现 MyContext.Provider
这个 API。
这也说明了,如果你不同步升级 react
与 react-dom
版本的话,就可能碰到这样的报错:fail saying these types are invalid,原因是 API 定义与实现不匹配。
setState 怎么调用平台实现
每个平台对 UI 更新逻辑的实现,会封装在 updater
函数里,所以不同平台代码会为组件添加各自的 updater
实现:
// Inside React DOM
const inst = new YourComponent();
inst.props = props;
inst.updater = ReactDOMUpdater;// Inside React DOM Server
const inst = new YourComponent();
inst.props = props;
inst.updater = ReactDOMServerUpdater;// Inside React Native
const inst = new YourComponent();
inst.props = props;
inst.updater = ReactNativeUpdater;
不同于 props
, updater
无法被直接调用,因为这个 API 是由 react 引擎在 setState
时调用的:
// A bit simplified
setState(partialState, callback) {// Use the `updater` field to talk back to the renderer!this.updater.enqueueSetState(this, partialState, callback);
}
关系可以这么描述:react
-> setState -> updater <- react-dom
等。
Hooks
Hooks 的原理与 setState
类似,当调用 useState
或 useEffect
时,其内部调用如下:
// In React (simplified a bit)
const React = {// Real property is hidden a bit deeper, see if you can find it!__currentDispatcher: null,useState(initialState) {return React.__currentDispatcher.useState(initialState);},useEffect(initialState) {return React.__currentDispatcher.useEffect(initialState);}// ...
};
ReactDOM 提供了 __currentDispatcher
(简化的说法):
// In React DOM
const prevDispatcher = React.__currentDispatcher;
React.__currentDispatcher = ReactDOMDispatcher;
let result;
try {result = YourComponent(props);
} finally {// Restore it backReact.__currentDispatcher = prevDispatcher;
}
可以看到,Hooks 的原理与 setState
基本一致,但需要注意 react
与 react-dom
之间传递了 dispatch
,虽然你看不到。但这个 dispatch
必须对应到唯一的 React 实例,这就是为什么 Hooks 不允许同时加载多个 React 实例的原因。
和 updater
一样,dispatch
也可以被各平台实现重写,比如 react-debug-hooks
就重写了 dispatcher。
由于需要同时实现 readContext
, useCallback
, useContext
, useEffect
, useImperativeMethods
, useLayoutEffect
, useMemo
, useReducer
, useRef
, useState
,工程量比较浩大,建议了解基本架构就足够了,除非你要深入参与 React 生态建设。
3 精读
与其他 React 分析文章不同,本文并没有过于刨根问题的上来就剖析 reconciler 实现,而是问了一个最基本的疑问:为什么 setState
来自 react
包,但实现却在 react-dom
里?React 是如何实现这个 magic 的?
通过这个疑问,我们了解了 React 更上层的抽象能力,如何用一个包制定规范,用 N 包去实现它。
接口的力量
在日常编程中,接口也拥有的强大力量,下面举几个例子。
UI 组件跨三端的接口
由于 RN、Weex、Flux 的某些不足,越来越多的人选择 “一个思想三端实现” 的方式做跨三端的 UI 组件,这样既兼顾了性能,又可以照顾到平台差异性,对不同平台组件细节做定制优化。
要实施这个方案,最大问题就是接口约定。一定要保证三套实现遵循同一套 API 接口,业务代码才可以实现 “针对任意一个平台编写,自动移植到其他平台”。
比较常用的做法是,通过一套统一的 API 文件约束,固定组件的输入输出,不同平台的组件做平台具体实现。这个思想和 React 如出一辙。
当然 RN 这些框架本身也是同一接口在不同平台实现的典型,只是做的不够彻底,JS 与 Native 的通信导致了性能不如源生。
通用数据查询服务
通用数据查询服务也比较流行,通过磨平各数据库语法,让用户通过一套 SQL 查询各种类型数据库的数据。
这个方案中,一套通用的查询语法就类似 React 定义的 API,执行阶段会转化为各数据库平台的 SQL 方言。
小程序融合方案
现在这种方案很火。通过基于 template 或者 jsx 的语法,一键发布到各平台小程序应用。
这种方案一定会抽象一套通用语法,甚至几乎等价与 react
与 react-dom
的关系:所有符合规范的语法,转化为各小程序平台的实现。
4 总结
这种分平台实现方案与跨平台方案还是有很大区别的,像 JAVA 虚拟机本质还是一套实现方案。而分平台的实现可以带来最原生的性能与体验,同样收到的约束也最大,应该其 API 应该是所有平台支持的一个子集。
另外,这种方案不仅可以用于 一套规范,不同平台的实现,甚至可以用在 “同一平台的实现”。
无论是公司还是开源节界,都有许多重复的轮子或者平台,如果通过技术委员会约定一套平台的实现规范,大家都遵循这个规范开发平台,那未来就比较好做收敛,或者说收敛的第一步都是先统一 API 规范。
留下一个思考题:还有没有利用 setState
规范与实现分离的思想案例?欢迎留下你的答案。
讨论地址是:精读《setState 做了什么》 · Issue #122 · dt-fe/weekly
如果你想参与讨论,请点击这里,每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。
来源:https://segmentfault.com/a/1190000017787272
转载于:https://www.cnblogs.com/lalalagq/p/10241717.html
精读《setState 做了什么》相关推荐
- 【韩松】Deep Gradient Comression_一只神秘的大金毛_新浪博客
<Deep Gradient Compression> 作者韩松,清华电子系本科,Stanford PhD,深鉴科技联合创始人.主要的研究方向是,神经网络模型压缩以及硬件架构加速. 论文链 ...
- 【韩松】Deep Gradient Comression
<Deep Gradient Compression> 作者韩松,清华电子系本科,Stanford PhD,深鉴科技联合创始人.主要的研究方向是,神经网络模型压缩以及硬件架构加速. 论文链 ...
- [文献阅读] Sparsity in Deep Learning: Pruning and growth for efficient inference and training in NN
文章目录 1. 前言 2. Overview of Sparsity in Deep Learning 2.1 Generalization 2.2 performance and model sto ...
- 【翻译】Batch Normalization: Accelerating Deep Network Trainingby Reducing Internal Covariate Shift
Batch Normalization: Accelerating Deep Network Trainingby Reducing Internal Covariate Shift Sergey I ...
- 模型加速--CLIP-Q: Deep Network Compression Learning by In-Parallel Pruning-Quantization
CLIP-Q: Deep Network Compression Learning by In-Parallel Pruning-Quantization CVPR2018 http://www.sf ...
- 论文笔记30 -- (视频压缩)【CVPR2021】FVC: A New Framework towards Deep Video Compression in Feature Space
<FVC: A New Framework towards Deep Video Compression in Feature Space> CVPR 2021 的一篇Oral 提出了特征 ...
- 端到端图像压缩《Asymmetric Gained Deep Image Compression With Continuous Rate Adaptation》
Asymmetric Gained Deep Image Compression With Continuous Rate Adaptation 一 简介 二 内容 2.1 目前方法的缺陷 2.2 整 ...
- 深度学习视频压缩1—DVC: An End-to-end Deep Video Compression Framework
本文是第一篇端到端使用神经网络来进行视频压缩的论文, github地址:GitHub - GuoLusjtu/DVC: DVC: An End-to-end Deep Video Compressio ...
- 【论文阅读】Deep Compositional Captioning: Describing Novel Object Categories without Paired Training Data
[论文阅读]Deep Compositional Captioning: Describing Novel Object Categories without Paired Training Data ...
- CVPR 2018 TRACA:《Context-aware Deep Feature Compression for High-speed Visual Tracking》论文笔记
理解出错之处望不吝指正. 本文的模型叫做TRACA.模型中使用多个expert auto-encoder,在预训练阶段,每个expert auto-encoder针对一个特定类进行训练:在tracki ...
最新文章
- 游戏让你额外多活10年#团队分享文字版
- 5 篇 AAAI 2018 论文看「应答生成」
- 监督学习 | 线性回归 之正则线性模型原理及Sklearn实现
- 实现三栏布局的几种方法
- 注释为基础的SpringMVC
- 连接两个std :: vector
- matlab用regress方法求ln函数_高中数学必背50条秒杀型公式和方法!高一高二高三都要看!...
- C#,SharpGL开发的3D图表控件
- Ruby On Rails简介
- ZynAddSubFX
- WRF users guide Chap5
- 发改委印发《关于促进分享经济发展的指导性意见》
- python plot画图函数_详解pandas.DataFrame.plot() 画图函数
- 风口起落的背后,是6271家创业公司的消亡
- 英语时态:一般、否定疑问句、现表将来
- 图灵学院python_Python——利用图灵创建聊天机器人
- java 删除注册表_java – 如何从Windows注册表中删除JRE条目?
- Day14 Date 包装类 Character
- HDU - 5976 Detachment(逆元)
- 机器学习之Matplotlib