@feng3d/reactivity 0.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +124 -26
  2. package/dist/index.js +1018 -58
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.umd.cjs +1017 -57
  5. package/dist/index.umd.cjs.map +1 -1
  6. package/lib/Reactivity.d.ts +69 -0
  7. package/lib/Reactivity.d.ts.map +1 -0
  8. package/lib/arrayInstrumentations.d.ts +2 -0
  9. package/lib/arrayInstrumentations.d.ts.map +1 -0
  10. package/lib/baseHandlers.d.ts +5 -0
  11. package/lib/baseHandlers.d.ts.map +1 -0
  12. package/lib/batch.d.ts +23 -0
  13. package/lib/batch.d.ts.map +1 -0
  14. package/lib/collectionHandlers.d.ts +7 -0
  15. package/lib/collectionHandlers.d.ts.map +1 -0
  16. package/lib/computed.d.ts +94 -0
  17. package/lib/computed.d.ts.map +1 -0
  18. package/lib/effect.d.ts +52 -0
  19. package/lib/effect.d.ts.map +1 -0
  20. package/lib/index.d.ts +7 -18
  21. package/lib/index.d.ts.map +1 -1
  22. package/lib/property.d.ts +44 -0
  23. package/lib/property.d.ts.map +1 -0
  24. package/lib/reactive.d.ts +66 -0
  25. package/lib/reactive.d.ts.map +1 -0
  26. package/lib/ref.d.ts +41 -0
  27. package/lib/ref.d.ts.map +1 -0
  28. package/lib/shared/constants.d.ts +34 -0
  29. package/lib/shared/constants.d.ts.map +1 -0
  30. package/lib/shared/general.d.ts +36 -0
  31. package/lib/shared/general.d.ts.map +1 -0
  32. package/package.json +3 -2
  33. package/src/Reactivity.ts +126 -0
  34. package/src/arrayInstrumentations.ts +448 -0
  35. package/src/baseHandlers.ts +220 -0
  36. package/src/batch.ts +91 -0
  37. package/src/collectionHandlers.ts +298 -0
  38. package/src/computed.ts +201 -0
  39. package/src/effect.ts +108 -0
  40. package/src/index.ts +7 -200
  41. package/src/property.ts +223 -0
  42. package/src/reactive.ts +130 -0
  43. package/src/ref.ts +88 -0
  44. package/src/shared/constants.ts +41 -0
  45. package/src/shared/general.ts +109 -0
package/src/index.ts CHANGED
@@ -1,201 +1,8 @@
1
- /**
2
- * 创建响应式值的引用。
3
- *
4
- * @param value
5
- * @returns
6
- */
7
- export function ref<T>(value: T): { value: T }
8
- {
9
- return new ValueReactiveNode<T>(value);
10
- }
11
-
12
- /**
13
- * 创建计算属性的函数
14
- * 计算属性的值会根据其依赖的响应式数据自动更新
15
- * @param func 计算属性的 getter 函数
16
- * @returns 包含 value 属性的对象,用于获取计算属性的值
17
- */
18
- export function computed<T>(func: () => T): { value: T }
19
- {
20
- return new FunctionReactiveNode(func);
21
- }
22
-
23
- /**
24
- * 当前正在执行的反应式节点。
25
- */
26
- let activeReactiveNode: ReactiveNode;
27
-
28
- type ReactiveNodeLink = { node: ReactiveNode, value: any, next: ReactiveNodeLink };
29
-
30
- /**
31
- * 反应式节点。
32
- */
33
- class ReactiveNode<T = any>
34
- {
35
- /**
36
- * 父反应节点。
37
- *
38
- * 记录了哪些节点调用了当前节点。
39
- */
40
- parents = new Set<ReactiveNode>();
41
-
42
- /**
43
- * 是否脏,是否需要重新计算。
44
- */
45
- dirty = true;
46
-
47
- /**
48
- * 失效的子节点,需要在执行时检查子节点值是否发生变化。
49
- */
50
- invalidChildren: ReactiveNodeLink;
51
-
52
- /**
53
- * 当前节点值。
54
- */
55
- get value()
56
- {
57
- this.run();
58
-
59
- return this._value;
60
- }
61
- protected _value: T;
62
-
63
- constructor()
64
- {
65
- }
66
-
67
- /**
68
- * 执行当前节点。
69
- */
70
- run()
71
- {
72
- const parentReactiveNode = activeReactiveNode;
73
- activeReactiveNode = this;
74
-
75
- let node = this.invalidChildren;
76
- while (node)
77
- {
78
- if (node.value !== node.node.value)
79
- {
80
- this.markDirty();
81
- }
82
-
83
- node = node.next;
84
- }
85
- this.invalidChildren = undefined as any;
86
-
87
- //
88
- // 保存当前节点作为父节点。
89
- // 设置当前节点为父节点。
90
- if (this.dirty)
91
- {
92
- this._value = this._runSelf();
93
-
94
- // 连接父节点和子节点。
95
- if (parentReactiveNode)
96
- {
97
- this.parents.add(parentReactiveNode);
98
- }
99
- //
100
- this.dirty = false;
101
- }
102
-
103
- // 执行完毕后恢复父节点。
104
- activeReactiveNode = parentReactiveNode;
105
- }
106
-
107
- /**
108
- * 标记为脏,触发更新。
109
- */
110
- markDirty()
111
- {
112
- if (this.dirty)
113
- {
114
- return;
115
- }
116
- this.dirty = true;
117
-
118
- this.invalidate();
119
-
120
- //
121
- this.parents.clear();
122
- }
123
-
124
- invalidate()
125
- {
126
- //
127
- if (this.parents.size > 0)
128
- {
129
- this.parents.forEach((parent) =>
130
- {
131
- const node: ReactiveNodeLink = { node: this, value: this._value, next: parent.invalidChildren };
132
- parent.invalidChildren = node;
133
- parent.invalidate();
134
- });
135
- }
136
- }
137
-
138
- /**
139
- * 执行当前节点自身。
140
- */
141
- protected _runSelf(): T
142
- {
143
- return this._value;
144
- }
145
- }
146
-
147
- /**
148
- * 反应式函数节点。
149
- *
150
- * 当使用 computed 函数时,会创建一个 ReactiveFunctionNode 对象。
151
- *
152
- * 当获取value值时,会执行func函数,返回结果。
153
- */
154
- class FunctionReactiveNode<T> extends ReactiveNode
155
- {
156
- /**
157
- * 监听的函数。
158
- */
159
- func: () => T;
160
-
161
- constructor(func: () => T)
162
- {
163
- super();
164
- this.func = func;
165
- }
166
-
167
- protected _runSelf()
168
- {
169
- return this.func();
170
- }
171
- }
172
-
173
- /**
174
- * 属性值反应式节点。
175
- *
176
- * 当使用 reactive 函数创建一个反应式对象后,访问该对象的属性时,会创建一个 ReactiveGetValueNode 对象。
177
- *
178
- * 当设置反应式对象对应属性值时,会触发该节点。
179
- */
180
- class ValueReactiveNode<V> extends ReactiveNode<V>
181
- {
182
- get value()
183
- {
184
- this.run();
185
-
186
- return this._value;
187
- }
188
- set value(v: V)
189
- {
190
- if (this._value === v) return;
191
- this.markDirty();
192
- this._value = v;
193
- }
194
-
195
- constructor(value: V)
196
- {
197
- super();
198
- this._value = value;
199
- }
200
- }
1
+ export { batchRun } from './batch';
2
+ export { ComputedReactivity as ComputedDep, computed, type Computed } from './computed';
3
+ export { Reactivity as Dep, forceTrack, noTrack } from './Reactivity';
4
+ export { EffectReactivity as EffectDep, effect, type Effect } from './effect';
5
+ export { isProxy, isReactive, reactive, type Reactive } from './reactive';
6
+ export { RefReactivity, isRef, ref, type Ref } from './ref';
7
+ export { toRaw } from './shared/general';
201
8
 
@@ -0,0 +1,223 @@
1
+ import { batchRun } from './batch';
2
+ import { Reactivity } from './Reactivity';
3
+ import { ARRAY_ITERATE_KEY, ITERATE_KEY, MAP_KEY_ITERATE_KEY, TrackOpTypes, TriggerOpTypes } from './shared/constants';
4
+ import { isArray, isIntegerKey, isMap, isSymbol } from './shared/general';
5
+
6
+ /**
7
+ * 反应式属性。
8
+ *
9
+ * @param target 对象。
10
+ * @param key 属性
11
+ * @returns 反应式属性。
12
+ */
13
+ function property<T, K extends keyof T>(target: T, key: K)
14
+ {
15
+ let depsMap = PropertyReactivity._targetMap.get(target);
16
+ if (!depsMap)
17
+ {
18
+ depsMap = new Map();
19
+ PropertyReactivity._targetMap.set(target, depsMap);
20
+ }
21
+
22
+ //
23
+ let dep = depsMap.get(key);
24
+ if (!dep)
25
+ {
26
+ dep = new PropertyReactivity(target, key);
27
+ depsMap.set(key, dep);
28
+ }
29
+
30
+ return dep;
31
+ }
32
+
33
+ /**
34
+ * 属性反应式节点。
35
+ */
36
+ export class PropertyReactivity<T, K extends keyof T> extends Reactivity<T>
37
+ {
38
+ /**
39
+ * 获取当前节点值。
40
+ *
41
+ * 取值时将会建立与父节点的依赖关系。
42
+ */
43
+ get value(): T
44
+ {
45
+ this.track();
46
+
47
+ return this._value;
48
+ }
49
+ set value(v)
50
+ {
51
+ // 处理特殊字段,这些字段
52
+ if (this._key === 'length')
53
+ {
54
+ v = this._target['length'];
55
+ }
56
+ else if (isSymbol(this._key))
57
+ {
58
+ v = ~~this._value + 1 as any;
59
+ }
60
+ if (v === this._value) return;
61
+ // 触发属性的变化。
62
+ this.trigger();
63
+ this._value = v;
64
+ }
65
+
66
+ private _target: T;
67
+ private _key: K;
68
+
69
+ constructor(target: T, key: K)
70
+ {
71
+ super();
72
+ this._target = target;
73
+ this._key = key;
74
+ if (target instanceof Map
75
+ || target instanceof WeakMap
76
+ )
77
+ {
78
+ this._value = (target as any as WeakMap<any, any>).get(key);
79
+ }
80
+ else if (target instanceof Set
81
+ || target instanceof WeakSet
82
+ )
83
+ {
84
+ this._value = (target as any as WeakSet<any>).has(key) as any;
85
+ }
86
+ else
87
+ {
88
+ this._value = (target as any)[key as any];
89
+ }
90
+ }
91
+
92
+ triggerIfChanged()
93
+ {
94
+
95
+ }
96
+
97
+ /**
98
+ * 追踪属性的变化。
99
+ *
100
+ * 当属性被访问时,将会追踪属性的变化。
101
+ *
102
+ * @param target 目标对象。
103
+ * @param key 属性名。
104
+ * @returns
105
+ */
106
+ static track(target: object, type: TrackOpTypes, key: unknown): void
107
+ {
108
+ const dep = property(target as any, key as any);
109
+
110
+ // 取值,建立依赖关系。
111
+ dep.track();
112
+ }
113
+ /**
114
+ * @private
115
+ */
116
+ static _targetMap: WeakMap<any, Map<any, PropertyReactivity<any, any>>> = new WeakMap();
117
+
118
+ /**
119
+ * 触发属性的变化。
120
+ *
121
+ * @param target 目标对象。
122
+ * @param type 操作类型。
123
+ * @param key 属性名。
124
+ * @param newValue 新值。
125
+ * @param oldValue 旧值。
126
+ * @returns
127
+ */
128
+ static trigger(target: object, type: TriggerOpTypes, key?: unknown, newValue?: unknown, oldValue?: unknown): void
129
+ {
130
+ const depsMap = this._targetMap.get(target);
131
+ if (!depsMap) return;
132
+
133
+ const run = (dep: PropertyReactivity<any, any> | undefined) =>
134
+ {
135
+ if (dep)
136
+ {
137
+ // 触发属性的变化。
138
+ dep.value = newValue;
139
+ }
140
+ };
141
+
142
+ batchRun(() =>
143
+ {
144
+ if (type === TriggerOpTypes.CLEAR)
145
+ {
146
+ // collection being cleared
147
+ // trigger all effects for target
148
+ depsMap.forEach(run);
149
+ }
150
+ else
151
+ {
152
+ const targetIsArray = isArray(target);
153
+ const isArrayIndex = targetIsArray && isIntegerKey(key);
154
+
155
+ if (targetIsArray && key === 'length')
156
+ {
157
+ const newLength = Number(newValue);
158
+ depsMap.forEach((dep, key) =>
159
+ {
160
+ if (
161
+ key === 'length'
162
+ || key === ARRAY_ITERATE_KEY
163
+ || (!isSymbol(key) && key >= newLength)
164
+ )
165
+ {
166
+ run(dep);
167
+ }
168
+ });
169
+ }
170
+ else
171
+ {
172
+ // schedule runs for SET | ADD | DELETE
173
+ if (key !== undefined || depsMap.has(undefined))
174
+ {
175
+ run(depsMap.get(key));
176
+ }
177
+
178
+ // schedule ARRAY_ITERATE for any numeric key change (length is handled above)
179
+ if (isArrayIndex)
180
+ {
181
+ run(depsMap.get(ARRAY_ITERATE_KEY));
182
+ }
183
+
184
+ // also run for iteration key on ADD | DELETE | Map.SET
185
+ switch (type)
186
+ {
187
+ case TriggerOpTypes.ADD:
188
+ if (!targetIsArray)
189
+ {
190
+ run(depsMap.get(ITERATE_KEY));
191
+ if (isMap(target))
192
+ {
193
+ run(depsMap.get(MAP_KEY_ITERATE_KEY));
194
+ }
195
+ }
196
+ else if (isArrayIndex)
197
+ {
198
+ // new index added to array -> length changes
199
+ run(depsMap.get('length'));
200
+ }
201
+ break;
202
+ case TriggerOpTypes.DELETE:
203
+ if (!targetIsArray)
204
+ {
205
+ run(depsMap.get(ITERATE_KEY));
206
+ if (isMap(target))
207
+ {
208
+ run(depsMap.get(MAP_KEY_ITERATE_KEY));
209
+ }
210
+ }
211
+ break;
212
+ case TriggerOpTypes.SET:
213
+ if (isMap(target))
214
+ {
215
+ run(depsMap.get(ITERATE_KEY));
216
+ }
217
+ break;
218
+ }
219
+ }
220
+ }
221
+ });
222
+ }
223
+ }
@@ -0,0 +1,130 @@
1
+ import { mutableHandlers } from './baseHandlers';
2
+ import { mutableCollectionHandlers } from './collectionHandlers';
3
+ import { Computed } from './computed';
4
+ import { Ref } from './ref';
5
+ import { ReactiveFlags, TargetType } from './shared/constants';
6
+ import { getTargetType, isObject, Target } from './shared/general';
7
+
8
+ /**
9
+ * 创建或者获取响应式对象的代理对象。
10
+ *
11
+ * @param target 被响应式的对象。
12
+ * @returns 响应式代理对象。
13
+ *
14
+ * 注意:
15
+ *
16
+ * 扩大被反应式的对象的类型范围,只有`Object.isExtensible`不通过的对象不被响应化。Float32Array等都允许被响应化。
17
+ */
18
+ export function reactive<T extends object>(target: T): Reactive<T>
19
+ {
20
+ if (!isObject(target))
21
+ {
22
+ return target;
23
+ }
24
+
25
+ if (target[ReactiveFlags.RAW])
26
+ {
27
+ return target as any;
28
+ }
29
+
30
+ // only specific value types can be observed.
31
+ const targetType = getTargetType(target);
32
+ if (targetType === TargetType.INVALID)
33
+ {
34
+ return target as any;
35
+ }
36
+
37
+ // target already has corresponding Proxy
38
+ const existingProxy = reactiveMap.get(target);
39
+ if (existingProxy)
40
+ {
41
+ return existingProxy;
42
+ }
43
+
44
+ const proxy = new Proxy<T>(
45
+ target,
46
+ targetType === TargetType.COLLECTION ? mutableCollectionHandlers : mutableHandlers as any,
47
+ ) as T;
48
+ reactiveMap.set(target, proxy);
49
+
50
+ return proxy as any;
51
+ }
52
+ export const reactiveMap = new WeakMap<Target, any>();
53
+
54
+ /**
55
+ * 判断一个对象是否为响应式对象。
56
+ *
57
+ * @param value 对象。
58
+ * @returns
59
+ */
60
+ export function isReactive(value: unknown): boolean
61
+ {
62
+ return !!(value && (value as Target)[ReactiveFlags.IS_REACTIVE]);
63
+ }
64
+
65
+ /**
66
+ * 转换为响应式对象。
67
+ *
68
+ * @param value 对象。
69
+ * @returns
70
+ */
71
+ export const toReactive = <T>(value: T): T =>
72
+ {
73
+ if (isObject(value))
74
+ {
75
+ return reactive(value as any) as any;
76
+ }
77
+
78
+ return value;
79
+ };
80
+
81
+ /**
82
+ * 判断一个对象是否为代理对象。
83
+ *
84
+ * @param value 对象。
85
+ * @returns
86
+ */
87
+ export function isProxy(value: any): boolean
88
+ {
89
+ return value ? !!value[ReactiveFlags.RAW] : false;
90
+ }
91
+
92
+ export type Reactive<T> = UnwrapRefSimple<T>;
93
+
94
+ /**
95
+ * 原始类型
96
+ */
97
+ type Primitive = string | number | boolean | bigint | symbol | undefined | null;
98
+ /**
99
+ * 内置类型
100
+ */
101
+ export type Builtin = Primitive | Function | Date | Error | RegExp;
102
+
103
+ /**
104
+ * 用于扩展不被 unwrap 的类型。
105
+ *
106
+ * ``` ts
107
+ * declare module '@vue/reactivity' {
108
+ * export interface RefUnwrapBailTypes {
109
+ * runtimeDOMBailTypes: Node | Window
110
+ * }
111
+ * }
112
+ * ```
113
+ */
114
+ export interface RefUnwrapBailTypes { }
115
+
116
+ /**
117
+ * 解包类型。
118
+ */
119
+ export type UnwrapRefSimple<T> =
120
+ T extends
121
+ | Builtin
122
+ | Ref
123
+ | RefUnwrapBailTypes[keyof RefUnwrapBailTypes]
124
+ ? T :
125
+ T extends Ref<infer TT> ? TT :
126
+ T extends Computed<infer TT> ? TT :
127
+ T extends object ? {
128
+ [K in keyof T]: UnwrapRefSimple<T[K]>
129
+ } :
130
+ T;
package/src/ref.ts ADDED
@@ -0,0 +1,88 @@
1
+ import { batchRun } from './batch';
2
+ import { Reactivity } from './Reactivity';
3
+ import { toReactive } from './reactive';
4
+ import { ReactiveFlags } from './shared/constants';
5
+ import { hasChanged, toRaw } from './shared/general';
6
+
7
+ /**
8
+ * 创建一个引用,该引用的值可以被响应式系统追踪和更新。
9
+ *
10
+ * @param value 引用的值。
11
+ * @returns 包含 value 属性的对象,用于获取和设置引用的值。
12
+ */
13
+ export function ref<T>(value?: T): Ref<T>
14
+ {
15
+ if (isRef(value))
16
+ {
17
+ return value as any;
18
+ }
19
+
20
+ return new RefReactivity<T>(value) as any;
21
+ }
22
+
23
+ /**
24
+ * 判断一个对象是否为引用。
25
+ * @param r 引用。
26
+ */
27
+ export function isRef<T>(r: Ref<T> | unknown): r is Ref<T>;
28
+ export function isRef(r: any): r is Ref
29
+ {
30
+ return r ? r[ReactiveFlags.IS_REF] === true : false;
31
+ }
32
+
33
+ export interface RefReactivity<T = any> extends Ref<T> { }
34
+
35
+ /**
36
+ * 引用反应式节点。
37
+ *
38
+ * 当使用 ref 函数时,会创建一个 RefReactivity 对象。
39
+ */
40
+ export class RefReactivity<T = any> extends Reactivity<T> implements Ref<T>
41
+ {
42
+ public readonly [ReactiveFlags.IS_REF] = true;
43
+
44
+ get value()
45
+ {
46
+ this.track();
47
+
48
+ return this._value;
49
+ }
50
+
51
+ set value(v: T)
52
+ {
53
+ const oldValue = this._rawValue;
54
+ const newValue = toRaw(v);
55
+
56
+ if (!hasChanged(oldValue, newValue)) return;
57
+
58
+ batchRun(() =>
59
+ {
60
+ this.trigger();
61
+
62
+ this._rawValue = newValue;
63
+ this._value = toReactive(newValue);
64
+ });
65
+ }
66
+
67
+ /**
68
+ * 原始值。
69
+ *
70
+ * 用于比较值是否发生变化。
71
+ */
72
+ private _rawValue: T;
73
+
74
+ constructor(value: T)
75
+ {
76
+ super();
77
+ this._rawValue = toRaw(value);
78
+ this._value = toReactive(value);
79
+ }
80
+ }
81
+
82
+ export interface Ref<T = any, S = T>
83
+ {
84
+ get value(): T
85
+ set value(_: S)
86
+ [RefSymbol]: true
87
+ }
88
+ declare const RefSymbol: unique symbol;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * 响应式标志枚举,用于标识响应式对象的特殊属性或状态
3
+ */
4
+ export enum ReactiveFlags
5
+ {
6
+ IS_REACTIVE = '__v_isReactive', // 标识对象是否为响应式对象
7
+ RAW = '__v_raw', // 获取对象的原始非响应式版本
8
+ IS_REF = '__v_isRef', // 标识对象是否为 ref 对象
9
+ }
10
+
11
+ export enum TargetType
12
+ {
13
+ INVALID = 0,
14
+ COMMON = 1,
15
+ COLLECTION = 2,
16
+ }
17
+
18
+ /**
19
+ * 跟踪操作类型枚举,用于标识在响应式系统中对对象属性进行的操作类型
20
+ */
21
+ export enum TrackOpTypes
22
+ {
23
+ GET = 'get', // 获取属性值
24
+ HAS = 'has', // 检查属性是否存在
25
+ ITERATE = 'iterate', // 遍历对象属性
26
+ }
27
+
28
+ /**
29
+ * 触发操作类型枚举,用于标识在响应式系统中对对象属性进行的修改操作类型
30
+ */
31
+ export enum TriggerOpTypes
32
+ {
33
+ SET = 'set', // 设置属性值
34
+ ADD = 'add', // 添加新属性
35
+ DELETE = 'delete', // 删除属性
36
+ CLEAR = 'clear', // 清空对象属性
37
+ }
38
+
39
+ export const ITERATE_KEY: unique symbol = Symbol(__DEV__ ? 'Object iterate' : '');
40
+ export const MAP_KEY_ITERATE_KEY: unique symbol = Symbol(__DEV__ ? 'Map keys iterate' : '');
41
+ export const ARRAY_ITERATE_KEY: unique symbol = Symbol(__DEV__ ? 'Array iterate' : '');