diff --git a/packages/reactive-signal/package-lock.json b/packages/reactive-signal/package-lock.json index add4e006a..a07afde68 100644 --- a/packages/reactive-signal/package-lock.json +++ b/packages/reactive-signal/package-lock.json @@ -1,12 +1,12 @@ { "name": "reactive-signal", - "version": "1.0.2", + "version": "1.0.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "reactive-signal", - "version": "1.0.2", + "version": "1.0.4", "license": "MIT", "devDependencies": { "@babel/eslint-parser": "^7.19.1", diff --git a/packages/reactive-signal/package.json b/packages/reactive-signal/package.json index 2311bc893..078432662 100644 --- a/packages/reactive-signal/package.json +++ b/packages/reactive-signal/package.json @@ -1,6 +1,6 @@ { "name": "reactive-signal", - "version": "1.0.3", + "version": "1.0.4", "scripts": { "start": "vite", "dev-vite": "vite", diff --git a/packages/reactive-signal/src/reactivity.ts b/packages/reactive-signal/src/reactivity.ts index 7a3fc4933..29740d212 100644 --- a/packages/reactive-signal/src/reactivity.ts +++ b/packages/reactive-signal/src/reactivity.ts @@ -54,7 +54,18 @@ export function signal(initialValue?: T): SignalValue { get(_, prop: keyof SignalValue) { if (prop === 'value') { if (activeEffect) { - deps.add(activeEffect) + // activeEffect.originalFn 如果存在就不添加到 deps + let added = false + for (const dep of deps) { + // @ts-ignore + if (dep.originalFn === activeEffect.originalFn) { + added = true + break + } + } + if (!added) { + deps.add(activeEffect) + } activeEffect.deps?.add({ value, deps }) // Add the dependency to the active effect } const component = getActiveComponent() @@ -104,7 +115,10 @@ export function signal(initialValue?: T): SignalValue { export function computed(fn: ComputedFn): SignalValue { const computedSignal = signal() effect(() => { - computedSignal.value = fn() + const newValue = fn() + if (computedSignal.peek() !== newValue) { + computedSignal.value = newValue + } }) return computedSignal } @@ -123,11 +137,14 @@ export function effect(fn: EffectFn): () => void { if (isRunning) return // If the effect function is already running, return directly isRunning = true // Start running the effect function activeEffect = effectFn - fn() + // 防止 effect 重复执行 + batch(() => { + fn() + }) activeEffect = null isRunning = false // Finish running the effect function }, - { deps }, + { deps, originalFn: fn }, ) // Run the effect function for the first time, which will collect dependencies diff --git a/packages/reactive-signal/test/reactivity.test.jsx b/packages/reactive-signal/test/reactivity.test.jsx index 04de96540..c01d82431 100644 --- a/packages/reactive-signal/test/reactivity.test.jsx +++ b/packages/reactive-signal/test/reactivity.test.jsx @@ -44,6 +44,44 @@ describe('computed', () => { expect(computedSignal.peek()).toBe(60) }) + it('should exec correct times', () => { + + const count = signal(0) + // Create a computed signal + const doubleCount = computed(() => count.value * 2) + let times = 0 + // Create an effect + effect(() => { + times++ + console.log(` ${count.value} Double Count: ${doubleCount.value}`) + }) + + // Update the count signal + count.value = 1 + expect(times).toBe(2) + + }) + + + it('should exec correct times', () => { + + const count = signal(0) + // Create a computed signal + const doubleCount = computed(() => count.value * 2) + const doubleDoubleCount = computed(() => doubleCount.value * 2) + let times = 0 + // Create an effect + effect(() => { + times++ + console.log(` ${count.value} Double Count: ${doubleCount.value}`) + }) + + // Update the count signal + count.value = 1 + expect(times).toBe(2) + + }) + it('should not dead loop', () => { const todos = signal([ { text: 'Learn OMI', completed: true },