diff --git a/src/index.ts b/src/index.ts index 148516e..70166dd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ export * from "./core"; export * from "./deepSignal"; export * from "./watch" +export * from "./watchEffect" export { isArray, isDate, diff --git a/src/test/watch.test.ts b/src/test/watch.test.ts index 2e942e1..589c5b9 100644 --- a/src/test/watch.test.ts +++ b/src/test/watch.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from "vitest"; import { deepSignal } from "../deepSignal"; import { watch } from "../watch"; +import { watchEffect } from "../watchEffect"; describe('watch', () => { it('watch immediate', () => { @@ -61,4 +62,20 @@ describe('watch', () => { expect(val).not.toEqual("jon") expect(val).toEqual("tom") }) + + it('watch effect', () => { + const store = deepSignal({ + userinfo: { + name: "tom" + } + }) + let x = undefined + watchEffect(() => { + x = store.userinfo.name + }) + + expect(x).toEqual("tom") + store.userinfo.name = "jon" + expect(x).toEqual("jon") + }) }) diff --git a/src/watch.ts b/src/watch.ts index f4a3fb0..2da2ee8 100644 --- a/src/watch.ts +++ b/src/watch.ts @@ -1,5 +1,5 @@ import { Computed, Effect, isSignal, Signal } from './core'; -import { hasChanged, isArray, isMap, isObject, isPlainObject, isSet, NOOP } from './utils'; +import { hasChanged, isArray, isFunction, isMap, isObject, isPlainObject, isSet, NOOP } from './utils'; import { isDeepSignal, isShallow } from "./deepSignal" import { ReactiveFlags } from './contents'; @@ -23,6 +23,39 @@ export type WatchCallback = ( const INITIAL_WATCHER_VALUE = {} let activeWatcher!: Effect +// const resetTrackingStack: (Subscriber | undefined)[] = [] + +// export let activeSub: Subscriber | undefined = undefined + +// export function setActiveSub(sub: Subscriber | undefined): void { +// activeSub = sub +// } +// /** +// * Temporarily pauses tracking. +// */ +// export function pauseTracking(): void { +// resetTrackingStack.push(activeSub) +// activeSub = undefined +// } + +// /** +// * Resets the previous global effect tracking state. +// */ +// export function resetTracking(): void { +// if (process.env.NODE_ENV !== 'production' +// && resetTrackingStack.length === 0) { +// console.warn( +// `resetTracking() was called when there was no active tracking ` + +// `to reset.`, +// ) +// } +// if (resetTrackingStack.length) { +// activeSub = resetTrackingStack.pop()! +// } else { +// activeSub = undefined +// } +// } + export const remove = (arr: T[], el: T): void => { const i = arr.indexOf(el) if (i > -1) { @@ -41,7 +74,7 @@ export function watch( let getter!: () => any let forceTrigger = false let isMultiSource = false - + // let cleanup = NOOP const signalGetter = (source: object) => { // traverse will happen in wrapped getter below if (deep) return source @@ -82,8 +115,31 @@ export function watch( return signalGetter(s) } }) - } - else { + } else if (isFunction(source)) { + if (cb) { + // getter with cb + getter = (source as () => any) + } else { + // no cb -> simple effect + getter = () => { + // if (cleanup) { + // pauseTracking() + // try { + // cleanup() + // } finally { + // resetTracking() + // } + // } + const currentEffect = activeWatcher + activeWatcher = effect + try { + return source(effect.stop) + } finally { + activeWatcher = currentEffect + } + } + } + } else { getter = NOOP if (process.env.NODE_ENV !== 'production') { console.warn( @@ -157,7 +213,6 @@ export function watch( return watchHandle } - export function traverse( value: unknown, depth: number = Infinity, diff --git a/src/watchEffect.ts b/src/watchEffect.ts new file mode 100644 index 0000000..6de28fc --- /dev/null +++ b/src/watchEffect.ts @@ -0,0 +1,5 @@ +import { watch } from "./watch" + +export function watchEffect(effect: () => void) { + return watch(effect, undefined) +}