feat: Every child node subscribe its parent.
This commit is contained in:
parent
04b12cc423
commit
ffd2bf2fc5
|
@ -13,6 +13,8 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
import { printNode } from './utils/printNode';
|
||||
|
||||
let runningRNode: RNode<any> | undefined = undefined; // 当前正执行的RNode
|
||||
let calledGets: RNode<any>[] | null = null;
|
||||
let sameGetsIndex = 0; // 记录前后两次运行RNode时,调用get顺序没有变化的节点
|
||||
|
@ -53,7 +55,7 @@ export class RNode<T = any> {
|
|||
private sources: RNode[] | null = null; // 使用谁
|
||||
|
||||
private state: State;
|
||||
private isEffect = false;
|
||||
isEffect = false;
|
||||
|
||||
|
||||
cleanups: ((oldValue: T) => void)[] = [];
|
||||
|
@ -102,6 +104,9 @@ export class RNode<T = any> {
|
|||
} else {
|
||||
calledGets.push(this);
|
||||
}
|
||||
if (process.env.NODE_ENV === 'debug') {
|
||||
console.log('Track: ', printNode(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -182,6 +187,10 @@ export class RNode<T = any> {
|
|||
this.cleanups = [];
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'debug') {
|
||||
console.log(`Running: ${printNode(this)}`);
|
||||
}
|
||||
|
||||
// 执行 reactive 函数
|
||||
this.execute();
|
||||
|
||||
|
@ -207,6 +216,10 @@ export class RNode<T = any> {
|
|||
} else {
|
||||
source.observers.push(this);
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'debug') {
|
||||
console.log(`Bind: ${printNode(this)} -> ${printNode(source)}`);
|
||||
}
|
||||
}
|
||||
} else if (this.sources && sameGetsIndex < this.sources.length) {
|
||||
// remove all old sources' .observers links to us
|
||||
|
@ -311,3 +324,4 @@ export function untrack(fn) {
|
|||
runningRNode = preRContext;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,17 +55,9 @@ export function getOrCreateChildRNode(node: RProxyNode<any>, key: string | symbo
|
|||
let child = node.children?.get(key);
|
||||
|
||||
if (!child) {
|
||||
// child = new RProxyNode(null, {
|
||||
// parent: node,
|
||||
// key: key,
|
||||
// root: node.root,
|
||||
// });
|
||||
|
||||
child = new RProxyNode(
|
||||
() => {
|
||||
const rootRNode = getRootRNode(node);
|
||||
// 依赖根
|
||||
rootRNode.get();
|
||||
node.get();
|
||||
|
||||
return getRNodeVal(node)[key];
|
||||
},
|
||||
|
@ -78,7 +70,5 @@ export function getOrCreateChildRNode(node: RProxyNode<any>, key: string | symbo
|
|||
);
|
||||
}
|
||||
|
||||
child.track();
|
||||
|
||||
return child;
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
*/
|
||||
|
||||
import { createProxy } from './proxy/RProxyHandler';
|
||||
import {getRNodeVal, getRootRNode, setRNodeVal} from './RNodeAccessor';
|
||||
import { getRNodeVal, getRootRNode, setRNodeVal } from './RNodeAccessor';
|
||||
import { preciseCompare } from './comparison/InDepthComparison';
|
||||
import { isObject } from './Utils';
|
||||
import {RNode, Root, runEffects} from "./RNode";
|
||||
import { RNode, Root, runEffects } from './RNode';
|
||||
|
||||
export interface RNodeOptions {
|
||||
root?: Root<any> | null;
|
||||
|
@ -83,13 +83,6 @@ export class RProxyNode<T = any> extends RNode<T> {
|
|||
}
|
||||
}
|
||||
|
||||
execute() {
|
||||
// 执行 reactive 函数
|
||||
if (this.isComputed) {
|
||||
setRNodeVal(this, this.fn!());
|
||||
}
|
||||
}
|
||||
|
||||
setByArrayModified(value: T) {
|
||||
const prevValue = this.getValue();
|
||||
|
||||
|
@ -104,7 +97,7 @@ export class RProxyNode<T = any> extends RNode<T> {
|
|||
}
|
||||
|
||||
getValue() {
|
||||
return getRNodeVal(this);
|
||||
return this._value;
|
||||
}
|
||||
|
||||
setValue(value: T) {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Huawei Technologies Co.,Ltd.
|
||||
*
|
||||
* openInula is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
import { RNode } from '../RNode';
|
||||
|
||||
export function printNode(signal: RNode) {
|
||||
let name: string;
|
||||
if (signal.fn) {
|
||||
if (signal.isEffect) {
|
||||
name = `Effect${signal.fn.name ?? ''}`;
|
||||
} else {
|
||||
name = `Computation(${(signal as unknown as any).key.toString()})`;
|
||||
}
|
||||
} else {
|
||||
name = 'Signal';
|
||||
|
||||
}
|
||||
return name;
|
||||
}
|
|
@ -63,6 +63,35 @@ describe('test reactive', () => {
|
|||
expect(yCalledTimes).toBe(2);
|
||||
});
|
||||
|
||||
it('overwrite object reactive should keep reactive', () => {
|
||||
const pos = reactive({ x: 0, y: 0 });
|
||||
|
||||
const xWatch = jest.fn();
|
||||
watch(() => {
|
||||
xWatch(pos.x.get());
|
||||
});
|
||||
const yWatch = jest.fn();
|
||||
watch(() => {
|
||||
yWatch(pos.y.get());
|
||||
});
|
||||
expect(xWatch).toBeCalledTimes(1);
|
||||
expect(yWatch).toBeCalledTimes(1);
|
||||
|
||||
pos.set({x: 1, y: 1});
|
||||
expect(xWatch).toBeCalledTimes(2);
|
||||
expect(yWatch).toBeCalledTimes(2);
|
||||
|
||||
pos.set({x: 2, y: 1});
|
||||
expect(xWatch).toBeCalledTimes(3);
|
||||
expect(yWatch).toBeCalledTimes(2);
|
||||
|
||||
pos.set({x: 2, y: 2});
|
||||
expect(xWatch).toBeCalledTimes(3);
|
||||
expect(yWatch).toBeCalledTimes(3);
|
||||
});
|
||||
|
||||
|
||||
|
||||
it('reactive is a obj', () => {
|
||||
const rObj = reactive({ count: 1 });
|
||||
|
||||
|
@ -110,7 +139,6 @@ describe('test reactive', () => {
|
|||
|
||||
a.set(2);
|
||||
expect(c.a.read()).toBe(2);
|
||||
|
||||
});
|
||||
|
||||
it('reactive is a array, watch', () => {
|
||||
|
|
Loading…
Reference in New Issue