这里在一定程度上参考了Vuex的文档,所以在一定程度上Tms合Vuex是十分相似的,不同的是Tms没有Vuex的Commit => Mutation
的概念,而是只有Commit
。
class Count extends Tms {
value: number = 0;
$setValue(value: number) {
this.value = value;
}
}
const count = new Count();
count.value; // => 0
在Tms中,每一个实例的可枚举属性,都被视为一个状态。你可以随意的读取实例的状态,但是不能随意的更改的实例的状态,否则导致实例的状态无法追踪。
切记:所有更新实例状态,都需要通过Commit
方法来进行更改,这样才能对实例状态变化的过程进行追踪。
😊 正确的写法,实例状态的变化,会变得可追踪
count.$setValue(1000);
😢 这是一种错误的写法,实例状态的变化,会变得无法追踪。
count.value = 1000;
class Count extends Tms {
value: number = 0;
get valueText (): string {
return `当前的value值是:${this.value}`;
}
}
如果在程序中,有很多地方都需要同样的数据,使用Getter
可以让我们的程序得到更好的优化。
-
1、更新实例的状态,必须在
Commit
方法中修改,所有以$开头为标志的方法,都会被认为是Commit
方法。😊
正确的:例子
class Count extends Tms { value: number = 0; $plus() { this.value++; } }
😢
错误的:例子
class Count extends Tms { value: number = 0; plus() { this.value++; } }
-
2、不能修改传入的载荷,只能赋值或复制一份对象。
😊
正确的:只赋值的例子
class List extends Tms { data: string[] = []; $loadDone(data: string[]) { this.data = data; } }
😢
错误的:修改了传入载荷的例子
class List extends Tms { data: string[] = []; $loadDone(data: string[]) { data.push('text'); this.data = data; } }
😊
正确的:复制一份对象,不对传入的载荷进行更改
class List extends Tms { data: string[] = []; $loadDone(data: string[]) { this.data = [ ...data, 'text' ]; } }
-
3、
Commit
必须是一个同步的方法,不能编写异步的代码、或者异步的更新状态。😊
正确的:同步的更新状态
class Count extends Tms { value: number = 0; $plus() { this.value++; } }
😢
错误的:在Commit中异步的更新状态
class Count extends Tms { value: number = 0; $plus() { setTimeout(() => { this.value++; }, 100); } }
在
Commit
异步的更新实例状态,将会导致状态变化的过程无法追踪,请将异步放到Action
中。😊
正确的:在Action中异步的更新状态
class Count extends Tms { value: number = 0; $plus() { this.value++; } plus() { setTimeout(() => { this.$plus(); }, 100); } }
Action专门负责所有的异步操作、比如定时器、HTTP请求等,它不负责更新状态,它将请求的结果提交给Commit
方法。
😊 正确的:一个HTTP请求查询的例子
interface Response {
code: number;
data: string [];
}
class Api {
getList(): Promise<Response> {
return new Promise((resolve) => {
resolve({
code: 0,
data: ['1', '2']
});
});
}
}
class List extends Tms {
api: Api;
loading: boolean = false
data: string[] = [];
constructor(api: Api) {
super();
this.api = api;
}
$loadStart() {
this.loading = true;
}
$loadDone(response: Response) {
if (response.code === 0) {
this.data = response.data;
}
this.loading = false;
}
async getList() {
this.$loadStart();
this.$loadDone(await this.api.getList());
}
}
const list = new List(new Api());
list.getList();
你应该将this.api.getList()
请求回来的完整数据,传入Commit
方法中,这样就能追踪到这个请求的结果。在Commit
方法中去对请求的结果进行处理。
同理,为了能够对所有的请求结果进行监听,所有的请求结果,都应该存储在实例上,通过Commit
更新实例的请求结果。
随着应用程序越来越大,我们需要对程序进行拆分成一个一个小的模块。
class Store extends Tms {
list: List = new List(new Api());
count: Count = new Count();
}
const store = new Store();
store.list.getList();
class Count extends Tms {
value: number = 0;
$setValue(value: number) {
this.value = value;
}
}
const count = new Count();
const onChange = (event: any) => {
console.log(event);
/**
{
type: '$setValue', // 触发的方法名称
payload: 100, // 提交的载荷,如果有多个,则取第一个
payloads: [ 100 ], // 提交的载荷
target: Count { value: 100 } // 触发事件的目标源
}
*/
};
// 订阅状态变化,在每个Commit方法执行完成后执行
count.dep.addSub(onChange);
count.$setValue(100);
// 销毁订阅
count.dep.removeSub(onChange);
Dep对象,提供了订阅实例状态和取消实例状态变化订阅的方法,通过这两个基础的API,你可以根据自己的需求进一步封装。