!124 fix: computed obj lost reactive
Merge pull request !124 from Hoikan/reactive-dev
This commit is contained in:
commit
d59a6770d1
|
@ -56,7 +56,7 @@ export class RNode<T = any> implements Signal<T> {
|
||||||
private observers: RNode[] | null = null; // 被谁用
|
private observers: RNode[] | null = null; // 被谁用
|
||||||
private sources: RNode[] | null = null; // 使用谁
|
private sources: RNode[] | null = null; // 使用谁
|
||||||
|
|
||||||
private state: State;
|
protected state: State;
|
||||||
isEffect = false;
|
isEffect = false;
|
||||||
|
|
||||||
cleanups: ((oldValue: T) => void)[] = [];
|
cleanups: ((oldValue: T) => void)[] = [];
|
||||||
|
@ -121,12 +121,6 @@ export class RNode<T = any> implements Signal<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
set(fnOrValue: T | ((prev: T) => T)): void {
|
set(fnOrValue: T | ((prev: T) => T)): void {
|
||||||
if (this.fn) {
|
|
||||||
this.removeParentObservers(0);
|
|
||||||
this.sources = null;
|
|
||||||
this.fn = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const prevValue = this.getValue();
|
const prevValue = this.getValue();
|
||||||
|
|
||||||
const value = isFunction(fnOrValue) ? fnOrValue(prevValue) : fnOrValue;
|
const value = isFunction(fnOrValue) ? fnOrValue(prevValue) : fnOrValue;
|
||||||
|
|
|
@ -16,15 +16,15 @@
|
||||||
import { isPrimitive } from './Utils';
|
import { isPrimitive } from './Utils';
|
||||||
import { RNode } from './RNode';
|
import { RNode } from './RNode';
|
||||||
import { Fn, NonFunctionType, Signal } from './Types';
|
import { Fn, NonFunctionType, Signal } from './Types';
|
||||||
import { Proxy, RProxyNode } from './RProxyNode';
|
import { DeepReactive, RProxyNode } from './RProxyNode';
|
||||||
import { getRNodeVal } from './RNodeAccessor';
|
import { getRNodeVal } from './RNodeAccessor';
|
||||||
|
|
||||||
export function createReactive<T extends string>(raw?: T): Signal<string>;
|
export function createReactive<T extends string>(raw?: T): Signal<string>;
|
||||||
export function createReactive<T extends number>(raw?: T): Signal<number>;
|
export function createReactive<T extends number>(raw?: T): Signal<number>;
|
||||||
export function createReactive<T extends symbol>(raw?: T): Signal<symbol>;
|
export function createReactive<T extends symbol>(raw?: T): Signal<symbol>;
|
||||||
export function createReactive<T extends number | string | symbol>(raw?: T): Signal<T>;
|
export function createReactive<T extends number | string | symbol>(raw?: T): Signal<T>;
|
||||||
export function createReactive<T extends Record<any, any> | Array<any> | symbol>(raw?: T): Proxy<T>;
|
export function createReactive<T extends Record<any, any> | Array<any> | symbol>(raw?: T): DeepReactive<T>;
|
||||||
export function createReactive<T extends NonFunctionType>(raw?: T): Proxy<T> | Signal<T> {
|
export function createReactive<T extends NonFunctionType>(raw?: T): DeepReactive<T> | Signal<T> {
|
||||||
if (isPrimitive(raw) || raw === null || raw === undefined) {
|
if (isPrimitive(raw) || raw === null || raw === undefined) {
|
||||||
return new RNode(raw, { isSignal: true });
|
return new RNode(raw, { isSignal: true });
|
||||||
} else {
|
} else {
|
||||||
|
@ -55,6 +55,12 @@ export function getOrCreateChildProxy(value: unknown, parent: RProxyNode<any>, k
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOrCreateChildRNode(node: RProxyNode<any>, key: string | symbol): RProxyNode<any> {
|
export function getOrCreateChildRNode(node: RProxyNode<any>, key: string | symbol): RProxyNode<any> {
|
||||||
|
if (node.isComputed && !node.parent) {
|
||||||
|
const root = node.read();
|
||||||
|
node.root = {
|
||||||
|
$: root
|
||||||
|
};
|
||||||
|
}
|
||||||
let child = node.children?.get(key);
|
let child = node.children?.get(key);
|
||||||
|
|
||||||
if (!child) {
|
if (!child) {
|
||||||
|
|
|
@ -14,13 +14,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createProxy } from './proxy/RProxyHandler';
|
import { createProxy } from './proxy/RProxyHandler';
|
||||||
import { getRNodeVal, getRootRNode, setRNodeVal } from './RNodeAccessor';
|
import { setRNodeVal } from './RNodeAccessor';
|
||||||
import { preciseCompare } from './comparison/InDepthComparison';
|
import { preciseCompare } from './comparison/InDepthComparison';
|
||||||
import { isObject } from './Utils';
|
import { isObject } from './Utils';
|
||||||
import { RNode, Root, runEffects } from './RNode';
|
import { Dirty, RNode, Root, runEffects } from './RNode';
|
||||||
import { Computation, ProxyRNode, Signal } from './Types';
|
import { Computation, Signal } from './Types';
|
||||||
|
|
||||||
export type Proxy<T> = T extends Record<string, unknown>
|
export type DeepReactive<T> = T extends Record<string, unknown>
|
||||||
? SignalProxy<T>
|
? SignalProxy<T>
|
||||||
: T extends () => infer Return
|
: T extends () => infer Return
|
||||||
? ComputationProxy<Return>
|
? ComputationProxy<Return>
|
||||||
|
@ -56,7 +56,7 @@ export class RProxyNode<T = any> extends RNode<T> {
|
||||||
key: KEY | null;
|
key: KEY | null;
|
||||||
children: Map<KEY, RProxyNode> | null = null;
|
children: Map<KEY, RProxyNode> | null = null;
|
||||||
|
|
||||||
proxy: Proxy<T> = null;
|
proxy: DeepReactive<T> = null;
|
||||||
|
|
||||||
extend: any; // 用于扩展,放一些自定义属性
|
extend: any; // 用于扩展,放一些自定义属性
|
||||||
|
|
||||||
|
@ -64,11 +64,9 @@ export class RProxyNode<T = any> extends RNode<T> {
|
||||||
|
|
||||||
constructor(fnOrValue: (() => T) | T, options?: RNodeOptions) {
|
constructor(fnOrValue: (() => T) | T, options?: RNodeOptions) {
|
||||||
super(fnOrValue, options);
|
super(fnOrValue, options);
|
||||||
|
|
||||||
this.isComputed = options?.isComputed || false;
|
this.isComputed = options?.isComputed || false;
|
||||||
|
|
||||||
// Proxy type should be optimized
|
// Proxy type should be optimized
|
||||||
this.proxy = createProxy as unknown as Proxy<T>;
|
this.proxy = createProxy(this) as unknown as DeepReactive<T>;
|
||||||
this.parent = options?.parent || null;
|
this.parent = options?.parent || null;
|
||||||
this.key = options?.key as KEY;
|
this.key = options?.key as KEY;
|
||||||
this.root = options?.root || {};
|
this.root = options?.root || {};
|
||||||
|
@ -119,6 +117,9 @@ export class RProxyNode<T = any> extends RNode<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue(value: T) {
|
setValue(value: T) {
|
||||||
|
if (this.parent) {
|
||||||
|
this.state = Dirty;
|
||||||
|
}
|
||||||
setRNodeVal(this, value);
|
setRNodeVal(this, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { getOrCreateChildProxy } from '../RNodeCreator';
|
||||||
import { getRNodeVal } from '../RNodeAccessor';
|
import { getRNodeVal } from '../RNodeAccessor';
|
||||||
import { isArray } from '../Utils';
|
import { isArray } from '../Utils';
|
||||||
import { RNode } from '../RNode';
|
import { RNode } from '../RNode';
|
||||||
import {Proxy, RProxyNode} from '../RProxyNode';
|
import { DeepReactive, RProxyNode } from '../RProxyNode';
|
||||||
|
|
||||||
const GET = 'get';
|
const GET = 'get';
|
||||||
const SET = 'set';
|
const SET = 'set';
|
||||||
|
@ -44,7 +44,7 @@ const MODIFY_ARR_FNS = new Set<string | symbol>([
|
||||||
// 数组的遍历方法
|
// 数组的遍历方法
|
||||||
const LOOP_ARR_FNS = new Set<string | symbol>(['forEach', 'map', 'every', 'some', 'filter', 'join']);
|
const LOOP_ARR_FNS = new Set<string | symbol>(['forEach', 'map', 'every', 'some', 'filter', 'join']);
|
||||||
|
|
||||||
export function createProxy<T extends RProxyNode>(proxyNode: T): Proxy<T> {
|
export function createProxy<T extends RProxyNode>(proxyNode: T): DeepReactive<T> {
|
||||||
return new Proxy(proxyNode, {
|
return new Proxy(proxyNode, {
|
||||||
get,
|
get,
|
||||||
set,
|
set,
|
||||||
|
|
|
@ -21,7 +21,7 @@ export function printNode(signal: RNode) {
|
||||||
if (signal.isEffect) {
|
if (signal.isEffect) {
|
||||||
name = `Effect${signal.fn.name ?? ''}`;
|
name = `Effect${signal.fn.name ?? ''}`;
|
||||||
} else {
|
} else {
|
||||||
name = `Computation(${(signal as unknown as any).key.toString()})`;
|
name = `Computation(${(signal as unknown as any).key?.toString() ?? ''})`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
name = 'Signal';
|
name = 'Signal';
|
||||||
|
|
|
@ -90,6 +90,32 @@ describe('test reactive', () => {
|
||||||
expect(yWatch).toBeCalledTimes(3);
|
expect(yWatch).toBeCalledTimes(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('overwrite array reactive should keep reactive', () => {
|
||||||
|
const pos = reactive([0, 0]);
|
||||||
|
|
||||||
|
const xWatch = jest.fn();
|
||||||
|
watch(() => {
|
||||||
|
xWatch(pos[0].get());
|
||||||
|
});
|
||||||
|
const yWatch = jest.fn();
|
||||||
|
watch(() => {
|
||||||
|
yWatch(pos[1].get());
|
||||||
|
});
|
||||||
|
expect(xWatch).toBeCalledTimes(1);
|
||||||
|
expect(yWatch).toBeCalledTimes(1);
|
||||||
|
|
||||||
|
pos.set([1, 1]);
|
||||||
|
expect(xWatch).toBeCalledTimes(2);
|
||||||
|
expect(yWatch).toBeCalledTimes(2);
|
||||||
|
|
||||||
|
pos.set([2, 1]);
|
||||||
|
expect(xWatch).toBeCalledTimes(3);
|
||||||
|
expect(yWatch).toBeCalledTimes(2);
|
||||||
|
|
||||||
|
pos.set([2, 2]);
|
||||||
|
expect(xWatch).toBeCalledTimes(3);
|
||||||
|
expect(yWatch).toBeCalledTimes(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
it('reactive is a obj', () => {
|
it('reactive is a obj', () => {
|
||||||
|
|
Loading…
Reference in New Issue