[xhook]让你的React开发体验更丝滑(基于rxjs和xstate)

783 阅读4分钟

xhook简介

为了实现状态管理的约束以及代码逻辑的进一步抽象,基于React hook引入xstate和rxjs分别用于状态管理和逻辑代码组织, 以此规避状态过度拆分导致的混乱、以及hooks使用过程中的一些心智负担。

github源码

示例代码

实现理念

1、响应事件 -> 变更状态 -> 响应事件 .... -> 变更状态

事件包括:组件加载、卸载,用户操作事件(点击),属性变更事件

使用React开发过程中,开发者所写的逻辑都是在处理数据的变化和响应用户的操作,抽象一下即响应事件、然后变更状态、再响应事件等等,一直循环往复下去。

【统一编程范式,所有的变化都转换成数据流】

借助rxjs数据流的理念,劫持组件事件将其转换为数据流,所有业务逻辑编程即对这些数据流的变化做出响应,通过操作符将业务逻辑进行拆分。

【约束状态及其变换过程】

借助xstate有限状态机的理念,事先声明好可枚举的状态及其变换过程,所有的状态统一管理,避免状态的碎片化。

状态机配置示例

2、所有环节都是“纯函数”

React hook带火了函数式编程,这种编程范式的优势很明显:借助纯函数的优势可以实现自由拼装和组合;rxjs也是一样采用函数式编程,通过一系列的操作符串联实现代码逻辑,而且每一个操作的都是纯函数,这意味着它拥有hook一样的优势。

这里的“纯函数”之所有加个引号,是因为我们还需要自己的操作符,而这些操作符或多或少都对执行环境有一些依赖,但在既定的环境下,我们仍然可以把它当成纯函数,享受纯函数带来的好处。

3、能不手写绝不手写

rxjs将逻辑拆分成一段一段的纯函数即操作符,用数据结构描述就是一个典型的有向带环图,操作符就是图的一个节点,这个结构很容易用图形化的方式描述出来。xstate也是类似的结构,官方已经提供了图形化的展示方式,如下图所示:

image.png

基于上述特点和优化,我们完全可以实现用可视化的方式绘制图形,然后再转换成代码,开发效率岂不是要高很多。

没错,就是大家常用的流程图,通过绘制流程的方式描述状态机和代码逻辑,实现流程即代码。

目前我们团队基于小程序的可视化开发平台已经完成,基于React的web开发正在进行中,请大家关注后续的分享

4、不要让我思考太多

React hook有个比较头疼的问题,就是过期的闭包,开发者在写代码的过程需要花费很大的心力来规避这个问题,实在是太反人性了。xhook通过hooks组合实现事件劫持,这种开发模式下,开发者只需要关注业务逻辑的实现,再也不用担心过期闭包的问题了。

API简介

api数量很少,共6个:1个组件包裹函数、6个hook、3个操作符

  1. 组件包裹函数 - withReactive
  2. 生命周期(加载)事件hook - useMount
  3. 生命周期(卸载)事件hook - useUnmount
  4. 用户操作事件hook - useEvenListen
  5. 自定义dom事件监听hook - useDomEvenListen
  6. 属性变更hook - useObserver
  7. 事件组合hook - useEventCompose
  8. 状态更新操作符 - update
  9. 状态机切换操作符 - transition
  10. 日志打印操作符 - log

详细文档请访问github仓库 《传送门》

示例

功能说明: 点击不同的按钮实现数字累加,如下图所示:

999999.gif

实现起来非常的便捷,useEventListen和useEventCompose就可以轻松搞定,而且逻辑也非常的清晰。

const Count = withReactive((props, state) => {
  const [addoneHandler, addone$] = useEventListen(ob$ => ob$.pipe(map(() => 1)), false);

  const [addtowHandler, addtwo$] = useEventListen(ob$ => ob$.pipe(map(() => 2)), false);

  const [addthreeHandler, addthree$] = useEventListen(ob$ => ob$.pipe(map(({ item }) => item[1])), false);

  useEventCompose(() => addone$.pipe(
    merge(addtwo$, addthree$),
    scan((prev, cur) => prev + cur, 0),
    update((data, total) => ({ total })),
  ));

  const num = props.num || 3;
  return (
    <div className="child">
      <div className="title">
        {props.tag}:{state.total}
      </div>
      <div className="btn-group">
        <button onClick={addoneHandler}>+1</button>
        <button onClick={addtowHandler}>+2</button>
        <button onClick={e => addthreeHandler(e, num)}>
          {num > 0 ? '+' : ''}
          {num}
        </button>
      </div>
    </div>
  );
});

学习资料

xstate学习资料

rxjs学习资料

欢迎有需要的朋友收藏,如有描述的不对或者需要改进的地方,欢迎大家帮忙指正,感谢!

github源码