diff --git a/packages/inula-reactive/src/RNode.ts b/packages/inula-reactive/src/RNode.ts index 869e9f42..a25677d3 100644 --- a/packages/inula-reactive/src/RNode.ts +++ b/packages/inula-reactive/src/RNode.ts @@ -13,6 +13,8 @@ * See the Mulan PSL v2 for more details. */ +import { printNode } from './utils/printNode'; + let runningRNode: RNode | undefined = undefined; // 当前正执行的RNode let calledGets: RNode[] | null = null; let sameGetsIndex = 0; // 记录前后两次运行RNode时,调用get顺序没有变化的节点 @@ -53,7 +55,7 @@ export class RNode { private sources: RNode[] | null = null; // 使用谁 private state: State; - private isEffect = false; + isEffect = false; cleanups: ((oldValue: T) => void)[] = []; @@ -102,6 +104,9 @@ export class RNode { } else { calledGets.push(this); } + if (process.env.NODE_ENV === 'debug') { + console.log('Track: ', printNode(this)); + } } } } @@ -182,6 +187,10 @@ export class RNode { this.cleanups = []; } + if (process.env.NODE_ENV === 'debug') { + console.log(`Running: ${printNode(this)}`); + } + // 执行 reactive 函数 this.execute(); @@ -207,6 +216,10 @@ export class RNode { } 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; } } + diff --git a/packages/inula-reactive/src/RNodeCreator.ts b/packages/inula-reactive/src/RNodeCreator.ts index 2cc5cbb9..5beb4ded 100644 --- a/packages/inula-reactive/src/RNodeCreator.ts +++ b/packages/inula-reactive/src/RNodeCreator.ts @@ -55,17 +55,9 @@ export function getOrCreateChildRNode(node: RProxyNode, 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, key: string | symbo ); } - child.track(); - return child; } diff --git a/packages/inula-reactive/src/RProxyNode.ts b/packages/inula-reactive/src/RProxyNode.ts index b943e585..0cca9941 100644 --- a/packages/inula-reactive/src/RProxyNode.ts +++ b/packages/inula-reactive/src/RProxyNode.ts @@ -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 | null; @@ -83,13 +83,6 @@ export class RProxyNode extends RNode { } } - execute() { - // 执行 reactive 函数 - if (this.isComputed) { - setRNodeVal(this, this.fn!()); - } - } - setByArrayModified(value: T) { const prevValue = this.getValue(); @@ -104,7 +97,7 @@ export class RProxyNode extends RNode { } getValue() { - return getRNodeVal(this); + return this._value; } setValue(value: T) { diff --git a/packages/inula-reactive/src/utils/printNode.ts b/packages/inula-reactive/src/utils/printNode.ts new file mode 100644 index 00000000..4bd1896b --- /dev/null +++ b/packages/inula-reactive/src/utils/printNode.ts @@ -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; +} diff --git a/packages/inula-reactive/tests/reactive.test.ts b/packages/inula-reactive/tests/reactive.test.ts index de444fb7..2ef0a4fb 100644 --- a/packages/inula-reactive/tests/reactive.test.ts +++ b/packages/inula-reactive/tests/reactive.test.ts @@ -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', () => {