核心概念
Observable
创建可订阅的对象,每次操作该对象属性的过程中会通知订阅者,使用proxy来创建
@formily/reactive中通过以下几个API来创建observable对象:
- observable函数创建深度的observable对象:
- observable.deep 创建深劫持observable对象
- observab.shallow 创建浅劫持observable对象
- observab.computed 创建缓存计算器
- observable.box 创建带get/set方法的observable对象
- observable.ref 创建引用级的observable对象
- define函数定义observable领域模型,可以组合observable函数与其其静态属性函数完成领域模型的定义
- model函数定义自动observable领域模型,他会将getter和setter属性包装为computed属性,将函数包为action,其他数据属性用observable(深劫持)包装
reaction
在响应式中它就是可订阅对象的订阅者,接收tracker函数,函数执行时如果函数内部对observable对象中的某个属性进行读操作,那么reaction就会与该属性进行一个绑定。一旦该属性在其他地方进行写操作就会重复执行tracker函数
创建reaction的API:
- autorun 创建一个自动执行的响应器
- reaction 创建一个可以实现脏检查的响应器
- Tracker 创建一个依赖追踪器,需用户手动执行追踪
测试用例
import React from 'react'
const obj = {
count: 1
}
const ReactivePage = () => {
const countAdd = () => {
obj.count++
console.log('count:',obj.count);
}
return (
<>
<h1>ReactivePage</h1>
<button onClick={countAdd}>{obj.count}</button>
</>
)
}
export default ReactivePage
点击button,log(count)一直加但是组件没更新 如何控制组件更新?
- 用observable(reactive)包裹obj
- 用observer(reactive-react)包裹ReactivePage
const obj = observable({
count: 1
})
export default observer(ReactivePage)
实现
hook
目的:让组件更新
import { useEffect, useReducer, useRef } from "react";
import { Tracker } from "../../../which";
export function useObserver(view) {
const [_, forceUpdate] = useReducer((i) => i + 1, 1);
//因为自定义hook会随着函数组件的更新多次执行,防止会多次实例化,将实例存起来,所以用useRef(存在对应组件的fiber上)
const trackerRef = useRef(null);
if (!trackerRef.current) {
//可变化对象的属性值发生变化,组件跟着更新。
//自己获取reaction
trackerRef.current = new Tracker(() => {
forceUpdate();
});
}
//组件卸载前取消订阅,防止内存泄露。
useEffect(() => {
return () => {
if(trackerRef.current){
trackerRef.current.dispose()
}
}
},[])
//创建组件的追踪器
return trackerRef.current.tracker(view)
}
observer
import { useObserver } from "./hook";
import { memo } from "react";
export default function observer(component) {
const WrappedComponent = (props) => {
return useObserver(() => component({ ...props }));
};
const memoComponent = memo(WrappedComponent);
return memoComponent;
}