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

业务背景目前团队内的开发模式多是面向组件的,UI层和逻辑层均强耦合在一起,由于业务的差异性,往往很难完全复用 。

  • 闲鱼前端业务处在高速发展不断尝试的阶段,如何能更快更稳定地完成需求,更好的支撑业务发展绝对是一个值得探索的问题 。
  • 在接手一个复杂的老业务代码时,经过较多人的修改,往往可维护性较差,有时只想修改某个小地方却需要较大的理解成本,所以用一套统一的组件开发规范在长期维护中显得格外重要 。
  • 闲鱼技术体系经历了从weex、rax0.x到现在rax1.x的变更,中间有过一些前端资产的积累,但是由于迁移的成本后期都不再维护,如何用更小的成本让业务层平稳过渡到新的技术体系?
对于以上的问题我们希望能用框架一并解决,对于该框架的目标主要包括:
  • 提高代码可复用性
  • 规范代码,降低长期维护成本
  • 降低业务层与技术体系的关联
 
思路关于提效,其中比较重要的是相同的代码不要重复写,做更细的区分和提取,提高可复用的颗粒度 。另一方面是解决现有开发下比较影响开发效率的问题 。
 
组件的分层所以我们将面向组件的开发模式分为UI层View和逻辑层Store,以Interface进行隔离和耦合 。
低成本可复用前端框架——Linke

文章插图
 
图一:组件构成
在UI层无需关心状态的流转,只负责展示和交互方法的调用,DOM相关的动画交互等行为逻辑也会放到该层中 。
低成本可复用前端框架——Linke

文章插图
 
图二:组件分工
在确认了分层的逻辑后自然就引入了Interface,主要分为两部分:一部分是IProps,申明该组件所需的Props,在使用者调用该组件时进行对应的提示和约束;另一部分则负责连接Store和View,其中包括状态state和交互方法;见下面的Interface示例:
export interface IMultiScrollerProps {tabs: string;onTabChange?(i: number): void;}export interface IMultiScroller extends IBase {readonly tabIndex: number;readonly tabSource: ITabItem;readonly children: any;onSwiperChange(i: number): void;}总结一下:所有的state和交互方法都在store中管理,供View消费;View中只负责和dom相关的逻辑操作,View和store的职责分界线就是View和store分别单独使用时其交互和效果都能保持不变;以此实现View和store分别能有更多的复用 。
 
状态管理现有的业务开发中基本所有的需求都是基于hooks的状态管理,主要存在以下问题:
  • 对于较复杂的组件hooks在多次迭代后的维护成本会非常高;
  • 有时候,你的useEffect依赖某个函数的不可变性,这个函数的不可变性又依赖于另一个函数的不可变性,这样便形成了一条依赖链 。一旦这条依赖链的某个节点意外地被改变了,那么useEffect就被意外地触发了后面的情况就会变得不可控 。
  • 异步陷阱
  • 状态的修改是异步的 useState返回的修改函数是异步的,并不会直接生效,所以此时读取该值获取到的是旧值 。要在下次重绘才能获取新值 。不要试图在更改状态之后立马获取状态 。
const [value, setValue] = useState(0);setValue(100);console.log(value); // <- 0•timeout指向的是旧值
timeout指向的是旧值,即使在外部已经重新设置,由于闭包所有在setTimeout中获取到的都是之前的值 。
const [value, setValue] = useState(0);window.setTimeout( => {console.log('setAnotherValue', value) // <- 0}, 1000);setValue(100);•何时使用useCallback/useMemo等对于新手来说存在一定的门槛 。
关于 Hook 中的闭包:useEffect、useMemo、useCallback都是自带闭包的 。也就是说,每一次组件的渲染,其都会捕获当前组件函数上下文中的状态(state、props) 。所以每一次这三种 Hook 的执行,反映的也都是当时的状态,无法获取最新的状态 。对于这种情况,应该使用 ref 来访问 。
对于状态管理react体系中最受欢迎的应是redux与mobx
低成本可复用前端框架——Linke

文章插图
 
图三:Redux Flow
redux的特点从上图可以总结得到下面的三大原则:
•单一数据源
•state 是只读的
•使用纯函数来执行修改
但是redux的问题也是十分明显的:开发者需要写更多附加的样板代码,并且留下更多需要我们维护的代码 。
与 Redux 相似的,另一个状态管理方案是 MobX:


推荐阅读