状态内监视
除了通过store.watch来监听状态外,还可以在状态内部声明watch函数来监听状态数据的变化。
工作原理
@autostorejs/react提供了watch函数,用来在state中声明一个监听对象,然后监听函数的返回值写入声明所在路径。

watch函数的基本特性如下:
- 在状态中的任意位置,使用
watch(...)来声明一个监听器对象。 - 在
createStore执行后,会扫描状态数据,如果发现一个值是watch(...),则会创建一个WatchObject对象,用来监听State中的数据变化。 - 创建的
WatchObject对象会保存在Store对象的watchObjects对象中 - 当所监听的数据发生变化时,会调用
WatchObject对象的getter函数,然后将返回结果写入到声明watch(...)的位置。
基本用法
watch函数签名如下:
ts
// 监听filter过滤后的
function watch<Value=any, DependValue=any>(
getter:WatchGetter<Value,DependValue>,
filter?:WatchDependFilter<DependValue>,
options?:Omit<WatchOptions<Value>,'filter'>
):WatchDescriptorBuilder<Value>
// 监听全部
function watch<Value=any, DependValue=any>(
getter:WatchGetter<Value,DependValue>,
options?:Omit<WatchOptions<Value>,'filter'>
):WatchDescriptorBuilder<Value>watch函数基本使用如下:
loading
在以上例子中,我们使用watch实现了computed的类似功能:
watch函数的第一个参数是getter函数,负责在依赖变化时计算新值。getter函数的返回值会写入watch函数所在的位置。watch函数的第二个参数是一个过滤函数,当状态变化时会调用此方法,如果返回true才会执行getterinitial属性用来配置watch函数所在位置的total的初始值。
监听函数
watch的getter参数只能是一个同步函数,签名如下:
typescript
type WatchGetter<Value=any,DependValue= any> = (
// 传入发生变化的路径和值
scope: {path:string[],value:DependValue},
// 创建的watchObject对象
watchObject : WatchObject<Value>
)=>Exclude<any,Promise<any>> | undefined监听参数
watch支持以下参数
ts
interface WatchOptions<Value=any> extends ObserverOptions<Value> {
async? : false
filter : WatchDependFilter<Value>
}initial: 用来指定一个默认值id: 用来指定一个唯一的标识,同时作为创建的WatchObject的key,可以通过store.watchObjects.get(<id>)来访问。
动态依赖
computed计算函数的依赖一般是确定的,而watch函数的依赖可以是动态的。这比较适合一些需要动态侦听的场景。
比如上例中,我们动态侦听orders[].count的变化来计算total。而computed函数的依赖是静态的,一旦声明就不会变化。
以下是表单validate检测的简单示例:
tsx
const store = createStore({
a:{
validate:true
},
b:{
validate:true
},
c:{
validate:true,
c1:{
validate:true
}
},
validate:watch<boolean,boolean>(({path,value},watchObj)=>{
if(typeof(value) === 'boolean'){
const srcKey = path.join('.')
if(value){
delete watchObj.cache[srcKey]
}else{
watchObj.cache[srcKey] = value
}
}
// 由于cache里面只记录validate=false的值,所以如果cache不为空则代表有字段的validate=false
return Object.keys(watchObj.cache).length==0
},
(path)=>path[path.length-1]=='validate', // 只侦听validate字段的值变化
{initial:true,id:"x"})
})说明:
- 上例中,我们需要实现一个
validate字段来表单整个表单的有效,当状态中任意一个对象中的validate字段都为false时,则validate=false,否则为true。 - 现在问题是
validate可能是在一个复杂的嵌套对象中,并且可能是动态的。这时候,我们无法使用computed来进行计算,因为computed的依赖是静态的。 - 此时就是使用
watch函数的时候了,我们声明一个watch函数,用来监听所有路径中的path[path.length-1]=='validate'字段的变化即可。 - 关于
WatchObject的介绍,可以参考监听对象。