锵锵锵~
小伙伴们,新出的会议室预约系统用着还顺手吗?快告诉我,对比之前的古老预定方式是不是方便很多?系统响应快不快?界面是不是一目了然?交互方式友好吗?
看着每天预约人数这么多,无疑答案都是肯定的。
那你有没有预约个会议室来把玩一下?预约网红会议室像不像淘宝双十一的大抢购?悄悄告诉你,会议室预约系统采用的前端框架,就是淘宝双十一的 Rax。爱学习的你一定嗅到了知识的味道~
那什么是 Rax,怎么用 Rax,什么时候用 Rax 呢?接下来,前端女同学就来聊聊会议室预约系统的前端技术使用。
1 What
什么是 Rax 呢,来看官方定义:Rax 是用于构建通用应用程序的渐进式 React 框架,其内部提供基础UI组件。目前,在阿里系公司展开使用,并在淘宝双十一购物节中独领风骚。
通过上面定义我们知道,Rax 是基于 React 标准,并支持在不同容器中渲染(当前最重要的容器即 Weex 和 Web )。
核心思想两个 “ React ” 标准和 “ 跨容器 ”。别问为什么,先记住,快,我知道你要问什么;因为接下来我要讲 Rax 和 React 的关系了,听完你就没有疑惑了。
1.1 Rax 和 React
我们可以把 React 看作是一种标准,那么Rax 就是对该标准的一个跨容器框架的实现。也可以说 Rax 只是 React 的无线端的解决方案,与 React 并无冲突,我们就把 Rax 看作是一种扩展,因为 Rax 与 React 还是有一定的区别。
比如:Rax 没有 createClass() 方法;Rax 可以返回多个同级结点,React 只能有一个结点;React 中的生命周期在 Rax 也同样可用,一些副作用和钩子函数均可使用。说到这些,你一定会想到 state,认为 state 状态的设计一定也一样,其实暗藏玄机(故意神秘)。
1.2 setState不同
Yeming say 结论先行,来,上结论。setState(updater, callback) 在 React 中是异步/同步的,而在 Rax 中是同步的。
先一起回顾一下 React 中怎么处理 setState 问题。
1.2.1 React 的 setState 机制
在 React 中,setState 后通常会集齐一批需要更新的组件,然后一次性更新来保证渲染的性能。
这也是通常操作,React 里面有两个更新 state 的方式,同步和异步。如果是由 React 事件引发的 setState(如 onClick 和钩子函数),调用 setState 是异步更新,除此之外的 setState 是同步执行(如 addEventListener 和定时器等)
React 会把每一次的 setState 操作放入一个队列里面,会先判断是否由 React 事件引发的 setState ,来判断是直接更新还是批量更新。
先对 React 事件进行标记,将 setState 传入的 state 参数存储在当前组件实例的 _pendingStateQueue 中;
将 React 事件引发的 setState 更新放入异步队列中并 dirty 标记,需要批量更新 state,把 VDom 到 Dom 的操作降到最小;
非 React 事件引发的 setState ,进行同步执行直接更新;
1.2.2 Rax 的 setState 机制
Rax 的 setState 为同步更新。只要调用 setState 就会直接更新对应的状态。
然而 setState 是会引起视图的更新会引发重绘。也就是会重新走一遍更新阶段的生命周期,这样一来势必会带来性能问题,这时候就需要开发者需要控制好更新时机,要不然系统就会卡卡卡卡卡卡。也是正因如此,Rax 对开发者的要求略高。
1.3 Rax 特点
- 设计上支持不同容器;
Rax 在设计上尽量抹平各个端的差异性,这也使得开发者在开发中,差异性和兼容性方面再也不需要投入太多精力。 - 体积足够小;
Rax 是一个面向无线端的解决方案,因此自身的体积对于性能来讲就显得非常重要。Rax 压缩 + gzip 后的体积是 8.0kb, 相比 React 的体积, 对于无线端很友好。 - 支持返回多个同级节点;
这一特性可以有效减少页面的嵌套层级,从而减少应用因嵌套层级过多而出现的 crash 问题。 - 标准化;
需要适配各个端,那么需要各个端的一致性,一致则必有规范可依,目前 Rax 遵循 W3C 标准,受限于各个端的差异,「更标准化」这也是 Rax 未来的重要目标之一。
1.4 多端运行机制
来,先上图
Rax 的跨容器特性是通过抽象出 View 层来实现的。
Rax 将 Vdom 与 Dom之间的转化抽象出 Driver,依靠 Driver 来驱动实现跨端。
Driver 定义了 VDOM 在具体容器下的渲染实现。比如在 Web 场景下,对应的 Driver 为 Driver-Dom,它描述了在浏览器中,如何将 VDOM 渲染为真实的 DOM。
正是基于这种思路,同一套代码,经过不同的 Driver 就可以运行在不同的容器下。
2 How
2.1 创建
快速创建一个 Rax 多端应用
npm init rax todoList
2.2 初始化
初始化项目过程中, 按照项目的需要选择配置信息。
以下是简单 todolist 的 demo 演示所需要的配置项。
2.3 项目目录
初始化的项目后,得到如下项目结构
├── README.md # 项目说明
├── build.json # 项目构建配置
├── package.json
└── src # 源码目录
├── app.js # 应用入口文件
├── app.json # 应用配置,包括路由配置,小程序 window 配置等
├── public # (可选)静态资源目录,会拷贝内容至 build 目录
├── components # 应用的公共组件
│ └── Logo # 组件
│ ├── index.css # Logo 组件的样式文件
│ └── index.jsx # Logo 组件 JSX 源码
├── document # 页面的 HTML 模板
│ └── index.jsx
└── pages # 页面
└── Home # home 页面
└── index.jsx
2.4 路由配置
Rax 使用 rax-use-router 来管理多个页面,生成的 Rax App 是一个单页应用(可通过 build-plugin-rax-multi-pages 切换成多页应用)
- 配置:路由的配置如同小程序的配置,在 app.json 中直接写入;
- 使用:路由正常使用,动态路由和路由对参数,不能直接从 props.id 获取,路由信息需要自己解析,不能像 react-router 那样,。
路由的配置信息如下图所示。
2.5 状态管理
状态管理方面可以采用和 React 相同的状态管理库,大致分为两类:
第一类:搭配中间件 Redux 状态管理,为了简化开发关注点,对 Redux 进一步封装,例如:Dva等等;
第二类:采用 observerble 的方案,例如:MobX 等;
如果使用状态管理的业务场景较少,可以考虑 React 的 Context ,官网推荐的 hooks 中 useContext + useReducer 搭配使用。具体的使用方案还是要看具体的业务需求。
2.6 组件传参
父 => 子:父组件可以通过 props 给子组件传递数据;
子 => 父:子组件可以通过 callBack 的方式调用父组件;
兄 <=> 弟:对于兄弟组件或者跨层组件,可以通过发事件的方式通信,也可以单独引入状态管理框架来处理。
当然了,也可以拿到组件的实例,使用 ref 直接调用相应的方法。
2.7 UI 组件库
Rax 的社区不够活跃,几乎没有可用的第三方 UI 组件库,仅有官方提供的一些常用功能组件,三大类组件库如下:
- 基础组件:如 View 视图组件,默认 Flexbox 布局,可任意嵌套;
- 基础容器:如 ScrollView 滚动容器,设置确定的高度展示列表内容;
- 功能组件:Embed 内嵌内容容器,在 Weex 容器中通过
<web>
实现,在 Web 容器中通过<iframe>
<embed>
实现;
2.8 打包
- 在 build.json 中选择一个或多个需要投放的端,目前可供选择的有 Web、 Weex、Alibaba Miniapp、WeChat MiniProgram、Kraken (Flutter);
- 运行npm run build 命令即可按需生成 build 打包文件。
miniapp => 阿里系小程序(支付宝小程序、天猫精灵小程序)
web => web 页面
weex => weex 容器
wechat-miprogram => 微信小程序
kraken => 一款轻量级的面向前端网络开发人员的框架
2.9 踩坑
(1)需要利用 PureComponent,StatelessComponent 优化组件渲染
Rax 把很多处理性能优化的工作交给了开发者来处理,这也是 Rax 对开发人员要求更高的一个原因。PureComponent 在更新触发时会比较 props 和 state,如果没变化就不更新。StatelessComponent 在组件渲染时不会生成 Component 实例,能减少一定性能开销;
(2)尽量自己来控制 Dom 的更新时机;
Rax 的 setState 是同步的,要避免频繁调用,最好是数据都统一更新,自己手动调用 forceUpdate 更新 Dom;
(3)子组件适当提供 Key,尽量保持组件 Dom 结构的稳定;
子组件设置 Key 和 Vue 原理类似的,保持 Dom 结构稳定,也和虚拟 Dom 的 Diff 有关,可以避免频繁的 Dom 操作;
(4)Rax 无单位与 rem 单位等价,页面宽度默认是 750rem,各端兼容;
(5)路由传参,很遗憾,不支持 props.id 直接获取,路由信息需要自己解析;
3 When
Rax 优点 跨容器、高性能、轻量。
但是Rax本质上还只是属于UI层模式,在接入时应该注意和自己的底层框架解耦。并且Rax对开发者的要求较搞,如果没有一定的经验和规范约束,容易导致项目臃肿、结构混乱的问题。
目前在移动端React和Vue都有很高的占比,社区生态也都比较活跃。具体的选型可以结合团队的实际情况。
无论选择哪个框架,都需要认真研究框架原理,对框架的优缺点和潜在问题做到心里有数,如果能够掌握其运行机制就更棒了,这样在应对一些复杂需求和重大变化时才能游刃有余。