UNPKG

@threlte/core

Version:

A 3D framework for the web, built on top of Svelte and Three.js

118 lines (117 loc) 3.75 kB
import { untrack } from 'svelte'; import { fromStore } from 'svelte/store'; const signal = Symbol(); const isStore = (dep) => { return typeof dep?.subscribe === 'function'; }; const runObserve = (dependencies, callback, pre) => { const stores = dependencies().map((d) => { if (isStore(d)) { return fromStore(d); } return signal; }); const deps = $derived(dependencies().map((d, i) => { if (stores[i] === signal) return d; return stores[i].current; })); const effect = () => { // eslint-disable-next-line @typescript-eslint/no-unused-expressions deps; let cleanup = undefined; untrack(() => { cleanup = callback(deps); }); return cleanup; }; if (pre) { $effect.pre(effect); } else { $effect(effect); } }; /** * ### `observe` * * Observe multiple stores and reactive values and call a callback when they * change to trigger side effects. The callback can return a cleanup function * that will be called when the dependencies change again or when the effect * root (most likely a component) is destroyed. Under the hood, `observe` uses * Svelte's `$effect` to track dependencies and trigger the callback. For a * version that uses `$effect.pre`, use `observe.pre`. * * ```ts * const count = writable(0) * let name = $state('John') * * observe(() => [count, name], ([count, name]) => { * console.log(count, name) // 0 John * }) * ``` * * The callback can return a cleanup function that will be called when the * dependencies change again or when the component is destroyed. * * ```ts * const count = writable(0) * * observe(() => [count], ([count]) => { * console.log(count) // 0 * return () => { * console.log('cleanup') * } * }) * ``` * * @param dependencies - A function that returns an array of dependencies. * @param callback - A function that will be called with the current values of * the dependencies. The callback can return a cleanup function that will be * called when the dependencies change again or when the component is destroyed. */ const observePost = (dependencies, callback) => { return runObserve(dependencies, callback, false); }; /** * ### `observe.pre` * * Observe multiple stores and reactive values and call a callback when they * change to trigger side effects. The callback can return a cleanup function * that will be called when the dependencies change again or when the effect * root (most likely a component) is destroyed. Under the hood, `observe.pre` uses * Svelte's `$effect` to track dependencies and trigger the callback. For a * version that uses `$effect`, use `observe`. * * ```ts * const count = writable(0) * let name = $state('John') * * observe.pre(() => [count, name], ([count, name]) => { * console.log(count, name) // 0 John * }) * ``` * * The callback can return a cleanup function that will be called when the * dependencies change again or when the component is destroyed. * * ```ts * const count = writable(0) * * observe.pre(() => [count], ([count]) => { * console.log(count) // 0 * return () => { * console.log('cleanup') * } * }) * ``` * * @param dependencies - A function that returns an array of dependencies. * @param callback - A function that will be called with the current values of * the dependencies. The callback can return a cleanup function that will be * called when the dependencies change again or when the component is destroyed. */ const observePre = (dependencies, callback) => { return runObserve(dependencies, callback, true); }; export const observe = Object.assign(observePost, { pre: observePre });