diff --git a/src/index.ts b/src/index.ts index f435b67c..00bc73a3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ export * from './defs/index.js'; export * from './manager.js'; +export * from './operators/index.js'; export * from './refs/index.js'; export * from './stores/index.js'; diff --git a/src/operators/index.ts b/src/operators/index.ts new file mode 100644 index 00000000..746caa70 --- /dev/null +++ b/src/operators/index.ts @@ -0,0 +1 @@ +export * from './watch.js'; diff --git a/src/operators/watch.ts b/src/operators/watch.ts new file mode 100644 index 00000000..9fbf9a7e --- /dev/null +++ b/src/operators/watch.ts @@ -0,0 +1,20 @@ +import { OffFn } from '@jujulego/event-tree'; + +import { Ref } from '../refs/index.js'; + +// Types +export type WatchCleanUp = () => void; +export type WatchFn = (data: D) => WatchCleanUp | undefined; + +// Operator +export function watch$(ref: Ref, fn: WatchFn): OffFn { + let cleanUp: WatchCleanUp | undefined; + + return ref.subscribe((data: D) => { + if (cleanUp) { + cleanUp(); + } + + cleanUp = fn(data); + }); +} diff --git a/tests/operators/watch.test.ts b/tests/operators/watch.test.ts new file mode 100644 index 00000000..e7d0729a --- /dev/null +++ b/tests/operators/watch.test.ts @@ -0,0 +1,42 @@ +import { vi } from 'vitest'; + +import { var$, watch$ } from '@/src/index.js'; + +// Tests +describe('watch$', () => { + it('should call fn when the reference changes', () => { + const ref = var$(); + const fn = vi.fn(); + + watch$(ref, fn); + ref.mutate(42); + + expect(fn).toHaveBeenCalledWith(42); + }); + + it('should call cb before next fn call', () => { + const ref = var$(); + const cb = vi.fn(); + + watch$(ref, () => cb); + ref.mutate(41); + + expect(cb).not.toHaveBeenCalled(); + + ref.mutate(42); + + expect(cb).toHaveBeenCalled(); + }); + + it('should not call fn if off has been called', () => { + const ref = var$(); + const fn = vi.fn(); + + const off = watch$(ref, fn); + off(); + + ref.mutate(42); + + expect(fn).not.toHaveBeenCalled(); + }); +}); \ No newline at end of file