1.0.1 • Published 6 years ago

qn-fe-core v1.0.1

Weekly downloads
-
License
ISC
Repository
-
Last release
6 years ago

Qiniu fe-core

前端基础库,定位是框架/界面库无关的基础工具,内容围绕状态管理方案实现,包括:

  • Disposable 类实现及基于 mobx 的 Store 类实现
  • 副作用(fetch / router / storage)与 Store 的绑定实现

fe-core 采用 Typescript 实现,对使用方没有要求,ES 项目中也可以引入 fe-core 并使用。

为什么

响应式编程(Reactive Programing)的好处

响应式编程的范式,适合实现状态随用户交互、时间变更的复杂应用逻辑。将应用的行为拆解为正交的两个部分:数据的维护逻辑与数据推导出的逻辑,便于逻辑的组织与实现。

例如,在 name 每次改变时打印出 name 的值:(这里以 MobX 提供的能力为例)

// 第一种方式,每次修改完手动调用 `console.log`,缺点:很难避免遗漏
o.name = 'foo'
console.log(o.name)

// 第二种方式,提供专门的用于修改 `name` 的方法,缺点:
// 要么不一致(有的值通过 `=` 有的值通过 `set` 方法)
// 要么繁琐(所有的值都要通过特定的 `set` 方法修改)
const o = {
	setName(name) {
		this.name = name
		console.log(name)
	}
}
o.name = 'foo'

// 基于响应式的数据,手动指定观测对象(依赖)
reaction(
	() => o.name,
	name => console.log(name)
)

// 基于响应式的数据,自动收集观测对象(依赖)
autorun(
	() => console.log(o.name)
)

再如,根据 firstNamelastName 计算得到 fullName

// 第一种方式,每次修改完 `firstName` 或 `lastName` 都记得重新计算 `fullName` 并赋值
// 缺点:繁琐且很难避免遗漏,有多少处对数据的修改,就需要维护多少处逻辑
o.firstName = 'foo'
o.lastName = 'bar'
o.fullName = getFullName(o.firstName, o.lastName)

// 第二种方式,提供专门的用于修改 `fistName` & `lastName` 的方法
// 缺点:有多少计算依赖,就需要实现多少处的 set 方法,需要维护 m * n 处逻辑
// (m 为 `fullName` 这样的复杂逻辑的数量,n 为逻辑依赖的数据项数)
const o = {
	setFirstName(firstName) {
		this.firstName = firstName
		this.updateFullName()
	}
	setLastName(lastName) {
		this.lastName = lastName
		this.updateFullName()
	}
	updateFullName() {
		this.fullName = getFullName(this.firstName, this.lastName)
	}
}

// 基于响应式的数据,声明数据间的映射关系
// 需要维护 m 处逻辑,即复杂逻辑的数量
class O {
	@computed get fullName() {
		return getFullName(this.firstName, this.lastName)
	}
}

数据驱动的好处

如果拥有了响应状态变更的能力,也就具备了将整个应用的行为都由状态变更来驱动的条件。而由状态数据来驱动应用行为,有这样的好处:

  1. 通过比较数据的值即可验证应用的状态与行为,可以大大简化开发时的调试与测试用例的编写
  2. 可以做到应用状态的保存与恢复,使一些复杂功能的实现变得简单(如开发辅助工具、用户操作状态恢复等)

为什么不使用业界主流方案或原生 API,而是通过与 Store 绑定后使用

如,为什么不使用 react-router,而使用 router-store 以及基于 router-store 实现的路由方案,原因有:

  • 使用数据的变更驱动与外界的交互,如这里的路由读取、跳转等行为
  • 将这部分状态(如这里的路由状态)纳入到统一的状态管理方案中,好处有 1. 同类逻辑形状的一致性 2. 数据流向的一致性 3. 支持推导与观测,方便其他部分使用

fe-core 采用的方案

  • 通过 Mobx 实现“透明地”(transparently)引入响应式编程范式。对比 Rx 等 FRP 框架:

    	1. 避免了显式的数据封装层,读写方式与 plain Javascript 一致,使用也更简洁
    	2. 舍弃了时间维度的信息,不便处理需要基于时间维度信息进行推导/响应的情况
    
    		一个简单而典型的例子是,单选组件的当前值由用户上一次操作选中值与可选列表的 default 项共同决定,取其中更新(发生更晚)者
  • 要求将数据变更实现为 action 函数,显式地标记为应用行为,实现限制与管理

  • 将 IO 行为(网络请求、本地存储、浏览器 URL 等)映射为不同的状态实例(Store),通过修改这些 Store 的数据实现对应副作用的触发

更多内容

内容

  • store/disposable

    	`Disposable` 类,收集对象销毁时需要执行的步骤。数据的观测底层实现依赖于事件,因此需要在对象被销毁的时候解除对应的监听逻辑。
  • store

    	基于 MobX 的状态容器 Store 类,提供 `dispose`、`snapshot` 及 `resume` 等能力
  • fetch-store

    	基于 Store 类的 fetch 绑定,将网络请求映射为数据
  • react-router-store

    	基于 Store 类的路由绑定,将浏览器的导航行为映射为数据
  • storage-store

    	基于 Store 类的 storage(localStorage/sessionStorage)绑定,将本地存储映射为数据

依赖安装

推荐使用 yarn 安装依赖

yarn install

开发相关

目前本地开发站点(如 financial)时无需构建本库,可直接使用源代码(ts 文件);构建用于发布 npm 包前。

npm run build # 构建
npm run test # 测试,TODO
npm run lint # 代码风格检查
npm run clean # 清理构建产物