xhook简介
为了实现状态管理的约束以及代码逻辑的进一步抽象,基于React hook引入xstate和rxjs分别用于状态管理和逻辑代码组织, 以此规避状态过度拆分导致的混乱、以及hooks使用过程中的一些心智负担。
实现理念
1、响应事件 -> 变更状态 -> 响应事件 .... -> 变更状态
事件包括:组件加载、卸载,用户操作事件(点击),属性变更事件
使用React开发过程中,开发者所写的逻辑都是在处理数据的变化和响应用户的操作,抽象一下即响应事件、然后变更状态、再响应事件等等,一直循环往复下去。
【统一编程范式,所有的变化都转换成数据流】
借助rxjs数据流的理念,劫持组件事件将其转换为数据流,所有业务逻辑编程即对这些数据流的变化做出响应,通过操作符将业务逻辑进行拆分。
【约束状态及其变换过程】
借助xstate有限状态机的理念,事先声明好可枚举的状态及其变换过程,所有的状态统一管理,避免状态的碎片化。
2、所有环节都是“纯函数”
React hook带火了函数式编程,这种编程范式的优势很明显:借助纯函数的优势可以实现自由拼装和组合;rxjs也是一样采用函数式编程,通过一系列的操作符串联实现代码逻辑,而且每一个操作的都是纯函数,这意味着它拥有hook一样的优势。
这里的“纯函数”之所有加个引号,是因为我们还需要自己的操作符,而这些操作符或多或少都对执行环境有一些依赖,但在既定的环境下,我们仍然可以把它当成纯函数,享受纯函数带来的好处。
3、能不手写绝不手写
rxjs将逻辑拆分成一段一段的纯函数即操作符,用数据结构描述就是一个典型的有向带环图,操作符就是图的一个节点,这个结构很容易用图形化的方式描述出来。xstate也是类似的结构,官方已经提供了图形化的展示方式,如下图所示:
基于上述特点和优化,我们完全可以实现用可视化的方式绘制图形,然后再转换成代码,开发效率岂不是要高很多。
没错,就是大家常用的流程图,通过绘制流程的方式描述状态机和代码逻辑,实现流程即代码。
目前我们团队基于小程序的可视化开发平台已经完成,基于React的web开发正在进行中,请大家关注后续的分享
4、不要让我思考太多
React hook有个比较头疼的问题,就是过期的闭包,开发者在写代码的过程需要花费很大的心力来规避这个问题,实在是太反人性了。xhook通过hooks组合实现事件劫持,这种开发模式下,开发者只需要关注业务逻辑的实现,再也不用担心过期闭包的问题了。
API简介
api数量很少,共6个:1个组件包裹函数、6个hook、3个操作符
- 组件包裹函数 - withReactive
- 生命周期(加载)事件hook - useMount
- 生命周期(卸载)事件hook - useUnmount
- 用户操作事件hook - useEvenListen
- 自定义dom事件监听hook - useDomEvenListen
- 属性变更hook - useObserver
- 事件组合hook - useEventCompose
- 状态更新操作符 - update
- 状态机切换操作符 - transition
- 日志打印操作符 - log
详细文档请访问github仓库 《传送门》
示例
功能说明: 点击不同的按钮实现数字累加,如下图所示:
实现起来非常的便捷,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>
);
});
学习资料
欢迎有需要的朋友收藏,如有描述的不对或者需要改进的地方,欢迎大家帮忙指正,感谢!