commit
f2bae1dd1f
|
@ -31,4 +31,4 @@ export {
|
|||
computed,
|
||||
isReactiveObj,
|
||||
untrack
|
||||
}
|
||||
};
|
||||
|
|
|
@ -26,7 +26,6 @@ export type State = typeof Fresh | typeof Check | typeof Dirty;
|
|||
type NonClean = typeof Check | typeof Dirty;
|
||||
|
||||
export interface RNodeOptions {
|
||||
root?: Root<any> | null;
|
||||
isSignal?: boolean;
|
||||
isEffect?: boolean;
|
||||
isComputed?: boolean;
|
||||
|
|
|
@ -17,7 +17,7 @@ import { isPrimitive } from './Utils';
|
|||
import { RNode } from './RNode';
|
||||
import { ProxyRNode } from './Types';
|
||||
import { RProxyNode } from './RProxyNode';
|
||||
import {getRNodeVal, getRootRNode} from "./RNodeAccessor";
|
||||
import { getRNodeVal, getRootRNode } from './RNodeAccessor';
|
||||
|
||||
export type Reactive<T = any> = RNode<T> | Atom<T>;
|
||||
|
||||
|
@ -61,18 +61,21 @@ export function getOrCreateChildRNode(node: RProxyNode<any>, key: string | symbo
|
|||
// root: node.root,
|
||||
// });
|
||||
|
||||
child = new RProxyNode(() => {
|
||||
const rootRNode = getRootRNode(node);
|
||||
// 依赖根
|
||||
rootRNode.get();
|
||||
child = new RProxyNode(
|
||||
() => {
|
||||
const rootRNode = getRootRNode(node);
|
||||
// 依赖根
|
||||
rootRNode.get();
|
||||
|
||||
return getRNodeVal(node)[key];
|
||||
}, {
|
||||
isComputed: true,
|
||||
parent: node,
|
||||
key: key,
|
||||
root: node.root,
|
||||
});
|
||||
return getRNodeVal(node)[key];
|
||||
},
|
||||
{
|
||||
isComputed: true,
|
||||
parent: node,
|
||||
key: key,
|
||||
root: node.root,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
child.track();
|
||||
|
|
|
@ -25,7 +25,7 @@ export interface RNodeOptions {
|
|||
isEffect?: boolean;
|
||||
isComputed?: boolean;
|
||||
isProxy?: boolean;
|
||||
parent?: RNode<any> | null;
|
||||
parent?: RProxyNode<any> | null;
|
||||
key?: KEY | null;
|
||||
equals?: (a: any, b: any) => boolean;
|
||||
}
|
||||
|
@ -55,14 +55,12 @@ export class RProxyNode<T = any> extends RNode<T> {
|
|||
this.key = options?.key as KEY;
|
||||
this.root = options?.root || {};
|
||||
|
||||
if (this.parent && !this.parent.children) {
|
||||
this.parent.children = new Map();
|
||||
if (this.parent) {
|
||||
if (!this.parent.children) {
|
||||
this.parent.children = new Map();
|
||||
}
|
||||
this.parent.children.set(this.key, this);
|
||||
}
|
||||
|
||||
if (this.isComputed) {
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
|
||||
compare(prevValue: any, value: any) {
|
||||
|
@ -109,7 +107,7 @@ export class RProxyNode<T = any> extends RNode<T> {
|
|||
return getRNodeVal(this);
|
||||
}
|
||||
|
||||
setValue(value: any) {
|
||||
setValue(value: T) {
|
||||
setRNodeVal(this, value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ export function isPrimitive(obj: unknown): boolean {
|
|||
return obj != null && type !== 'object' && type !== 'function';
|
||||
}
|
||||
|
||||
export function isFunction<T extends (...prev: any) => any>(obj: unknown): obj is T {
|
||||
export function isFunction<T extends (...prev: any) => any>(obj: unknown): obj is Function {
|
||||
return typeof obj === 'function';
|
||||
}
|
||||
|
||||
|
|
|
@ -1,31 +1,66 @@
|
|||
import { reactive, computed, watch } from '../index';
|
||||
|
||||
describe('test reactive', () => {
|
||||
it('two signals, one computed', () => {
|
||||
it('computation should work with two reactive', () => {
|
||||
const a = reactive(7);
|
||||
const b = reactive(1);
|
||||
let callCount = 0;
|
||||
|
||||
const c = computed(() => {
|
||||
const product = computed(() => {
|
||||
callCount++;
|
||||
return { a: a.get() * b.get() };
|
||||
return { value: a.get() * b.get() };
|
||||
});
|
||||
|
||||
watch(() => {
|
||||
console.log(a.get());
|
||||
});
|
||||
// computed should be lazy
|
||||
expect(callCount).toBe(0);
|
||||
|
||||
expect(a.read()).toBe(7);
|
||||
|
||||
a.set(2);
|
||||
expect(c.a.read()).toBe(2);
|
||||
expect(product.value.read()).toBe(2);
|
||||
|
||||
b.set(3);
|
||||
expect(c.a.get()).toBe(6);
|
||||
expect(product.value.get()).toBe(6);
|
||||
expect(callCount).toBe(2);
|
||||
|
||||
expect(callCount).toBe(3);
|
||||
c.read();
|
||||
expect(callCount).toBe(3);
|
||||
product.read();
|
||||
// computed function should not be invoked
|
||||
expect(callCount).toBe(2);
|
||||
});
|
||||
|
||||
it('computations should be triggered when source is same reactive', () => {
|
||||
const pos = reactive({ x: 0, y: 0 });
|
||||
let xCalledTimes = 0;
|
||||
let yCalledTimes = 0;
|
||||
|
||||
const x = computed(() => {
|
||||
xCalledTimes++;
|
||||
return pos.x.get();
|
||||
});
|
||||
|
||||
const y = computed(() => {
|
||||
yCalledTimes++;
|
||||
return pos.y.get();
|
||||
});
|
||||
|
||||
expect(x.read()).toBe(0);
|
||||
expect(y.read()).toBe(0);
|
||||
expect(xCalledTimes).toBe(1);
|
||||
expect(yCalledTimes).toBe(1);
|
||||
|
||||
// when pos.x changed, x should be triggered and y should not
|
||||
pos.x.set(1);
|
||||
expect(x.read()).toBe(1);
|
||||
expect(y.read()).toBe(0);
|
||||
expect(xCalledTimes).toBe(2);
|
||||
expect(yCalledTimes).toBe(1);
|
||||
|
||||
// when pos.y changed, y should be triggered and x should not
|
||||
pos.y.set(1);
|
||||
expect(x.read()).toBe(1);
|
||||
expect(y.read()).toBe(1);
|
||||
expect(xCalledTimes).toBe(2);
|
||||
expect(yCalledTimes).toBe(2);
|
||||
});
|
||||
|
||||
it('reactive is a obj', () => {
|
||||
|
|
Loading…
Reference in New Issue