代码
以下描述了类,以及依赖于类的一个指针变量
// arrays
const store = {
boxes:[],
arrrows:[],
selection:null
};
// classes
store.boxes.push(
new Box('Rotterdam',100,100),
new Box('Vienna',700,150),
);
store.arrows.push({
id:randomUuild(),
from:store.boxes[0],
to:store.boxes[1],
})
复制代码
Box的定义
class Box{
id = randomUuid();
@observable name = 'a box';
@observable x = 0 ;
@observable y = 0 ;
@observable get width(){
return this.name.length * 15;
}
constructor(name,x,y,id){
this.name = name ;
this.x = x ;
this.y = y ;
this.id = id || randomUuid();
}
}
复制代码
不可变数据结构 vs 可变的数据结构
不可变数据结构 | 响应式可变数据结构 |
---|---|
不会改变 | 身份平等 |
结构固定 | 概念在内存中应该仅存在一次 |
方便记忆,结构共享,没防御性拷贝,时间旅行 | 总是最新的 |
假设数据是一个树,不是一个图 | 组合和关联 |
非规范化其余部分 | 原型和类型检查 |
自然的心智模型 | |
简单的行为模式 |
可观察性 @observer
- mobservable.autorun(()=>this.render())
- autorun
-
- 引入一个方法,实现响应式
- 每次执行之后,运行时订阅数据可触达性
-
- 数据变化时重新执行
- 可控的依赖树
- 单纯的渲染混合函数
对比流程
改变 actions
- 直接的数据改变
- 不需要有上下文的意识
- 没有标准的模板需要遵循
其他的
时间旅行
autorun函数中使用serializeState 来存储(跟踪)所有的读写记录
const state = [] ;
autorun(()=>{
states.push(serializeState(store));
})
热加载
if(module.hot){
module.hot.accept();
if(module,hot.data && module.hot.data.store){
deserializeState(store,module.hot.data.store);
}
module.hot.dispose(data=>{
data.store = serializeState(store);
})
}
复制代码
核心api
@observable | 让成员变为响应式 |
---|---|
autorun | 创造一个字更新函数,使用响应式数据 |
@observer | 封装react组件的render方法在autorun函数中 |
如何底层实现的
- 装饰 所有的对象属性和数组指针
- 在栈中存储视图相关
- 数据读取注册到观察者
- 数据设置通知观察者
依赖树分析
-
订阅随时间改变
-
同步更新,支持事务机制
-
原子粒度的更新
-
循环检测
-
非纯视图的函数检测
-
懒汉和饿汉评估模式
-
垃圾回收