低成本可复用前端框架——Linke( 二 )


低成本可复用前端框架——Linke

文章插图
 
图四:Mobx Flow
相比 Redux 的强规则约定,MobX 更简单灵活,核心原理是通过 action 触发 state 的变化,进而触发 state 的衍生对象(Computed value & Reactions) 。开发者只需要定义需要 Observe 的数据和由此衍生的数据(Computed value)或者操作 (Reactions),剩下的更新就交给 MobX 去做就可以了 。一句话总结就是:
任何源自应用状态的东西都应该自动地获得 。
分析闲鱼的业务特色并不存在5个以上同学同时维护一个项目的超大型需求,强约定的redux对我们来说收益有限,而MobX 确实比 Redux 上手更容易些,并且不需要写很多样板代码,可以提供更高效的选择 。
 
实现我们给框架取名:Linke,来自switch的游戏塞尔达,希望它能像林克一样点亮一个个神庙 。
基于上面的分析思路结合实际业务中的技术体系(Rax)最后我们设计了下面的研发体系:UI部分也就是View还是沿用原有的Rax,UI用到的状态也直接在View中管理 。业务逻辑部分也就是Store用Mobx的能力解决上面提到的现有hooks开发遇到的问题,两者没有强关联 。
Linke做为中间耦合层对他们进行约束和桥接 。
低成本可复用前端框架——Linke

文章插图
 
图五:基于Linke的研发体系
 
API为保证开发者最低的学习成本,Linke在设计时尽可能地减少API,最终只有一个方法和4个Store内置方法,详见:
observer(baseComponent, Store)
保证组件能响应store中的可观察对象(observable)变更,即store更新,组件视图响应式更新
Store内置方法
•成员方法 - $$set: 所有状态变化必须通过$$set来完成,与微信的setData类似
•成员方法 - $$setProps:处理外部传入的组件props,View初始化或者props发生变化时调用
•成员方法 - $$didMount:提供View的生命周期,View被插入DOM时调用
•成员方法 - $$unMount:提供View的生命周期,View被移除DOM时调用 可以看出Store内置方法中除了$$set其他三个都是生命周期方法,其调用顺序为:$$setProps -> $$didMount -> $$unMount
 
demoInterface.ts
import { IBase } from '@ali/idlefish-linke';export interface IComponentProps { // 组件所需propstabs: string;onTabChange?(i: number): void;}export interface IComponent extends IBase { // 连接view和store的state&交互方法readonly items: any;handleLoadmore: void;}index.tsx
import { observer } from "@ali/idlefish-linke";import Store from './store';import { IComponent, IComponentProps } from './interface';function Component({items, handleLoadmore}: IComponent) {return (<View>{items.map(item => {return <Text>{item.title}</Text>})}<View onClick={handleLoadmore}>load more</View></View>)}export default observer<IComponentProps>(Component, Store);store.ts
import { makeAutoObservable } from "@ali/idlefish-linke";import { IComponent } from './interface';export default class ComponentStore implements IComponent {/*** 所有状态变化必须通过$$set来触发Effect* $$set赋值来自于makeAutoObservable(this);* this.$$set('items', [])*/$$set;/*** 带初始值的属性会自动被观测*/items: any = ;page: 1;constructor {// 自动observable该类makeAutoObservable(this);}$$setProps(props) {... // 对props的处理可以放到这里}$$didMount { // 通过 $$didMount / $$unMount 来感知view的生命周期this.fetch;}fetch{mtop.request('mtop.xxx', {page}).then(d => {this.$$set('items', d.list);})}handleLoadmore ==> {this.$$set('page', this.page++);this.fetch;}}上面就是一个完整的组件demo 。
 
对比现在的组件开发模块模式如下图六所示,以组件为单位所有的逻辑是耦合在一起的,相互之间没有分界,即便是相同的样式也很难实现复用 。无论是在代码理解还是二次开发上都存在较大的成本和不稳定性风险 。
低成本可复用前端框架——Linke

文章插图
 
图六:原组件的开发模式
基于Linke的组件开发模式如下图所示:
低成本可复用前端框架——Linke

文章插图
 
图七:基于Linke的组件开发模式
View和Store相对独立没有强耦合性,这样的好处显而易见:
• 通过阅读Interface就能知道Store/View的基本逻辑,减少理解成本
• 数据逻辑和View逻辑分别在Store和View中管理,真正实现各司其职,减少维护成本 。


推荐阅读