手摸手带你学Raxjs

锵锵锵~
小伙伴们,新出的会议室预约系统用着还顺手吗?快告诉我,对比之前的古老预定方式是不是方便很多?系统响应快不快?界面是不是一目了然?交互方式友好吗?
看着每天预约人数这么多,无疑答案都是肯定的。
那你有没有预约个会议室来把玩一下?预约网红会议室像不像淘宝双十一的大抢购?悄悄告诉你,会议室预约系统采用的前端框架,就是淘宝双十一的 Rax。爱学习的你一定嗅到了知识的味道~
那什么是 Rax,怎么用 Rax,什么时候用 Rax 呢?接下来,前端女同学就来聊聊会议室预约系统的前端技术使用。

手摸手带你学Raxjs_第1张图片

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 和定时器等)

手摸手带你学Raxjs_第2张图片

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 特点

  1. 设计上支持不同容器;
    Rax 在设计上尽量抹平各个端的差异性,这也使得开发者在开发中,差异性和兼容性方面再也不需要投入太多精力。
  2. 体积足够小;
    Rax 是一个面向无线端的解决方案,因此自身的体积对于性能来讲就显得非常重要。Rax 压缩 + gzip 后的体积是 8.0kb, 相比 React 的体积, 对于无线端很友好。
  3. 支持返回多个同级节点;
    这一特性可以有效减少页面的嵌套层级,从而减少应用因嵌套层级过多而出现的 crash 问题。
  4. 标准化;
    需要适配各个端,那么需要各个端的一致性,一致则必有规范可依,目前 Rax 遵循 W3C 标准,受限于各个端的差异,「更标准化」这也是 Rax 未来的重要目标之一。

1.4 多端运行机制

来,先上图手摸手带你学Raxjs_第3张图片
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 演示所需要的配置项。
手摸手带你学Raxjs_第4张图片

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 切换成多页应用)

  1. 配置:路由的配置如同小程序的配置,在 app.json 中直接写入;
  2. 使用:路由正常使用,动态路由和路由对参数,不能直接从 props.id 获取,路由信息需要自己解析,不能像 react-router 那样,。
    路由的配置信息如下图所示。
    手摸手带你学Raxjs_第5张图片

2.5 状态管理

状态管理方面可以采用和 React 相同的状态管理库,大致分为两类:
第一类:搭配中间件 Redux 状态管理,为了简化开发关注点,对 Redux 进一步封装,例如:Dva等等;
第二类:采用 observerble 的方案,例如:MobX 等;
如果使用状态管理的业务场景较少,可以考虑 React 的 Context ,官网推荐的 hooks 中 useContext + useReducer 搭配使用。具体的使用方案还是要看具体的业务需求。

2.6 组件传参

父 => 子:父组件可以通过 props 给子组件传递数据;
子 => 父:子组件可以通过 callBack 的方式调用父组件;
兄 <=> 弟:对于兄弟组件或者跨层组件,可以通过发事件的方式通信,也可以单独引入状态管理框架来处理。
当然了,也可以拿到组件的实例,使用 ref 直接调用相应的方法。

2.7 UI 组件库

Rax 的社区不够活跃,几乎没有可用的第三方 UI 组件库,仅有官方提供的一些常用功能组件,三大类组件库如下:

  1. 基础组件:如 View 视图组件,默认 Flexbox 布局,可任意嵌套;
  2. 基础容器:如 ScrollView 滚动容器,设置确定的高度展示列表内容;
  3. 功能组件:Embed 内嵌内容容器,在 Weex 容器中通过 实现,在 Web 容器中通过