锵锵锵~
小伙伴们,新出的会议室预约系统用着还顺手吗?快告诉我,对比之前的古老预定方式是不是方便很多?系统响应快不快?界面是不是一目了然?交互方式友好吗?
看着每天预约人数这么多,无疑答案都是肯定的。
那你有没有预约个会议室来把玩一下?预约网红会议室像不像淘宝双十一的大抢购?悄悄告诉你,会议室预约系统采用的前端框架,就是淘宝双十一的 Rax。爱学习的你一定嗅到了知识的味道~
那什么是 Rax,怎么用 Rax,什么时候用 Rax 呢?接下来,前端女同学就来聊聊会议室预约系统的前端技术使用。
什么是 Rax 呢,来看官方定义:Rax 是用于构建通用应用程序的渐进式 React 框架,其内部提供基础UI组件。目前,在阿里系公司展开使用,并在淘宝双十一购物节中独领风骚。
通过上面定义我们知道,Rax 是基于 React 标准,并支持在不同容器中渲染(当前最重要的容器即 Weex 和 Web )。
核心思想两个 “ React ” 标准和 “ 跨容器 ”。别问为什么,先记住,快,我知道你要问什么;因为接下来我要讲 Rax 和 React 的关系了,听完你就没有疑惑了。
我们可以把 React 看作是一种标准,那么Rax 就是对该标准的一个跨容器框架的实现。也可以说 Rax 只是 React 的无线端的解决方案,与 React 并无冲突,我们就把 Rax 看作是一种扩展,因为 Rax 与 React 还是有一定的区别。
比如:Rax 没有 createClass() 方法;Rax 可以返回多个同级结点,React 只能有一个结点;React 中的生命周期在 Rax 也同样可用,一些副作用和钩子函数均可使用。说到这些,你一定会想到 state,认为 state 状态的设计一定也一样,其实暗藏玄机(故意神秘)。
Yeming say 结论先行,来,上结论。setState(updater, callback) 在 React 中是异步/同步的,而在 Rax 中是同步的。
先一起回顾一下 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 ,进行同步执行直接更新;
Rax 的 setState 为同步更新。只要调用 setState 就会直接更新对应的状态。
然而 setState 是会引起视图的更新会引发重绘。也就是会重新走一遍更新阶段的生命周期,这样一来势必会带来性能问题,这时候就需要开发者需要控制好更新时机,要不然系统就会卡卡卡卡卡卡。也是正因如此,Rax 对开发者的要求略高。
来,先上图
Rax 的跨容器特性是通过抽象出 View 层来实现的。
Rax 将 Vdom 与 Dom之间的转化抽象出 Driver,依靠 Driver 来驱动实现跨端。
Driver 定义了 VDOM 在具体容器下的渲染实现。比如在 Web 场景下,对应的 Driver 为 Driver-Dom,它描述了在浏览器中,如何将 VDOM 渲染为真实的 DOM。
正是基于这种思路,同一套代码,经过不同的 Driver 就可以运行在不同的容器下。
快速创建一个 Rax 多端应用
npm init rax todoList
初始化项目过程中, 按照项目的需要选择配置信息。
以下是简单 todolist 的 demo 演示所需要的配置项。
初始化的项目后,得到如下项目结构
├── 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
Rax 使用 rax-use-router 来管理多个页面,生成的 Rax App 是一个单页应用(可通过 build-plugin-rax-multi-pages 切换成多页应用)
状态管理方面可以采用和 React 相同的状态管理库,大致分为两类:
第一类:搭配中间件 Redux 状态管理,为了简化开发关注点,对 Redux 进一步封装,例如:Dva等等;
第二类:采用 observerble 的方案,例如:MobX 等;
如果使用状态管理的业务场景较少,可以考虑 React 的 Context ,官网推荐的 hooks 中 useContext + useReducer 搭配使用。具体的使用方案还是要看具体的业务需求。
父 => 子:父组件可以通过 props 给子组件传递数据;
子 => 父:子组件可以通过 callBack 的方式调用父组件;
兄 <=> 弟:对于兄弟组件或者跨层组件,可以通过发事件的方式通信,也可以单独引入状态管理框架来处理。
当然了,也可以拿到组件的实例,使用 ref 直接调用相应的方法。
Rax 的社区不够活跃,几乎没有可用的第三方 UI 组件库,仅有官方提供的一些常用功能组件,三大类组件库如下:
实现,在 Web 容器中通过
实现;(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 直接获取,路由信息需要自己解析;
Rax 优点 跨容器、高性能、轻量。
但是Rax本质上还只是属于UI层模式,在接入时应该注意和自己的底层框架解耦。并且Rax对开发者的要求较搞,如果没有一定的经验和规范约束,容易导致项目臃肿、结构混乱的问题。
目前在移动端React和Vue都有很高的占比,社区生态也都比较活跃。具体的选型可以结合团队的实际情况。
无论选择哪个框架,都需要认真研究框架原理,对框架的优缺点和潜在问题做到心里有数,如果能够掌握其运行机制就更棒了,这样在应对一些复杂需求和重大变化时才能游刃有余。