diff --git a/src/index.ts b/src/index.ts index fa69a31..3b1191d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,3 @@ export * from "./core"; export * from "./deepSignal"; +export * from "./watch" diff --git a/src/test/index.test.ts b/src/test/index.test.ts index 5382b57..1f91692 100644 --- a/src/test/index.test.ts +++ b/src/test/index.test.ts @@ -1,7 +1,6 @@ import { deepSignal, peek, RevertDeepSignal, shallow } from "../index" -import { describe, it, expect, beforeEach, test } from "vitest" +import { describe, it, expect, beforeEach } from "vitest" import { signal, Signal, effect } from ".."; -import { watch } from "../watch"; type Store = { a?: number; nested: { b?: number }; @@ -1112,25 +1111,3 @@ describe("deepsignal/core", () => { }); }); }); - - -describe('watch', () => { - test('abc', () => { - const store = deepSignal({ - userinfo: { - name: "tom" - } - }) - const stop = watch(store, (newValue, oldValue) => { - console.log('newValue', newValue); - console.log('oldValue', oldValue); - }, { - immediate: true, - deep: true, - }) - - store.userinfo.name = "jon" - stop() - store.userinfo.name = 'jon2' - }) -}) diff --git a/src/test/watch.test.ts b/src/test/watch.test.ts new file mode 100644 index 0000000..2e942e1 --- /dev/null +++ b/src/test/watch.test.ts @@ -0,0 +1,64 @@ +import { describe, expect, it } from "vitest"; +import { deepSignal } from "../deepSignal"; +import { watch } from "../watch"; + +describe('watch', () => { + it('watch immediate', () => { + const store = deepSignal({ + userinfo: { + name: "tom" + } + }) + let val!: string + watch(store, (newValue) => { + val = newValue.userinfo.name + }, { + immediate: true, + deep: true + }) + expect(val).toEqual('tom') + }) + it('watch deep', () => { + const store = deepSignal({ + userinfo: { + name: "tom" + } + }) + let val!: string + watch(store, (newValue) => { + val = newValue.userinfo.name + }, { + immediate: true, + deep: true + }) + let value2!: string + watch(store, (newValue) => { + value2 = newValue.userinfo.name + }, { immediate: true }) + expect(val).toEqual('tom') + store.userinfo.name = "jon" + expect(val).toEqual('jon') + expect(value2).toEqual('tom') + }) + + it('watch once', () => { + const store = deepSignal({ + userinfo: { + name: "tom" + } + }) + let val!: string + watch(store, (newValue) => { + val = newValue.userinfo.name + }, { + immediate: true, + deep: true, + once: true + }) + + expect(val).toEqual("tom") + store.userinfo.name = "jon" + expect(val).not.toEqual("jon") + expect(val).toEqual("tom") + }) +}) diff --git a/src/utils.ts b/src/utils.ts index ef47787..5c45714 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,6 +1,3 @@ -import { ReactiveFlags } from "./contents" -import { isSignal } from "./core" - export const objectToString: typeof Object.prototype.toString = Object.prototype.toString export const toTypeString = (value: unknown): string => @@ -40,41 +37,3 @@ export const isPlainObject = (val: unknown): val is object => export const hasChanged = (value: any, oldValue: any): boolean => !Object.is(value, oldValue) - -export function traverse( - value: unknown, - depth: number = Infinity, - seen?: Set, -): unknown { - if (depth <= 0 || !isObject(value) || (value as any)[ReactiveFlags.SKIP]) { - return value - } - - seen = seen || new Set() - if (seen.has(value)) { - return value - } - seen.add(value) - depth-- - if (isSignal(value)) { - traverse(value.value, depth, seen) - } else if (isArray(value)) { - for (let i = 0; i < value.length; i++) { - traverse(value[i], depth, seen) - } - } else if (isSet(value) || isMap(value)) { - value.forEach((v: any) => { - traverse(v, depth, seen) - }) - } else if (isPlainObject(value)) { - for (const key in value) { - traverse(value[key], depth, seen) - } - for (const key of Object.getOwnPropertySymbols(value)) { - if (Object.prototype.propertyIsEnumerable.call(value, key)) { - traverse(value[key as any], depth, seen) - } - } - } - return value -} diff --git a/src/watch.ts b/src/watch.ts index 646e2f8..19d2a67 100644 --- a/src/watch.ts +++ b/src/watch.ts @@ -1,6 +1,7 @@ -import { Computed, Effect, isSignal, Signal, } from './core'; -import { hasChanged, isArray, traverse } from './utils'; +import { Computed, Effect, isSignal, Signal } from './core'; +import { hasChanged, isArray, isMap, isObject, isPlainObject, isSet } from './utils'; import { isDeepSignal, isShallow } from "./deepSignal" +import { ReactiveFlags } from './contents'; export type OnCleanup = (cleanupFn: () => void) => void export type WatchEffect = (onCleanup: OnCleanup) => void @@ -38,7 +39,6 @@ export function watch( let effect!: Effect let getter!: () => any - // let boundCleanup: typeof onWatcherCleanup let forceTrigger = false let isMultiSource = false @@ -150,3 +150,42 @@ export function watch( } return watchHandle } + + +export function traverse( + value: unknown, + depth: number = Infinity, + seen?: Set, +): unknown { + if (depth <= 0 || !isObject(value) || (value as any)[ReactiveFlags.SKIP]) { + return value + } + + seen = seen || new Set() + if (seen.has(value)) { + return value + } + seen.add(value) + depth-- + if (isSignal(value)) { + traverse(value.value, depth, seen) + } else if (isArray(value)) { + for (let i = 0; i < value.length; i++) { + traverse(value[i], depth, seen) + } + } else if (isSet(value) || isMap(value)) { + value.forEach((v: any) => { + traverse(v, depth, seen) + }) + } else if (isPlainObject(value)) { + for (const key in value) { + traverse(value[key], depth, seen) + } + for (const key of Object.getOwnPropertySymbols(value)) { + if (Object.prototype.propertyIsEnumerable.call(value, key)) { + traverse(value[key as any], depth, seen) + } + } + } + return value +}