Skip to content

Commit a5470f9

Browse files
feat: Export createReactiveFunction
1 parent f498564 commit a5470f9

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { ReactiveValue } from "./reactive-value";
2+
3+
/**
4+
* @typedef {() => void} VoidFn
5+
*/
6+
7+
/**
8+
* Used to synchronize external state with Svelte's reactivity system.
9+
*
10+
* In order to synchronize external state, you need to know two things:
11+
* - The value of the external state at a given time
12+
* - When you should update that value
13+
*
14+
* These correspond to the two arguments to this function:
15+
*
16+
* - {@link getSnapshot} is a function that returns the current value of the external state
17+
* - {@link onSubscribe} is a callback that sets up reactivity:
18+
* - It is called the first time the function returned by {@link createReactiveFunction} becomes tracked by a dependent
19+
* - It receives a function, `update`, as its first argument. Calling `update` tells Svelte that the value in the external
20+
* store has changed, and it needs to push that change to all of its listeners
21+
* - If it returns a cleanup function, that cleanup function will be called when the number of listeners to the reactive function
22+
* returns to zero
23+
*
24+
* Combined with `$derived.by`, this enables seamless integration with external data sources, including destructuring support:
25+
*
26+
* @example
27+
* ```js
28+
* import { observer } from 'external-datafetching-library';
29+
*
30+
* const { data, loading, refetch } = $derived.by(
31+
* createReactiveFunction(
32+
* observer.getCurrentResult,
33+
* observer.subscribe
34+
* )
35+
* );
36+
* ```
37+
*
38+
* (For our React friends, this is a similar model to `useSyncExternalStore`.)
39+
*
40+
* @template T
41+
* @param {() => T} getSnapshot
42+
* @param {(update: VoidFn) => void | VoidFn} onSubscribe
43+
* @returns {() => T}
44+
*/
45+
export function createReactiveFunction(getSnapshot, onSubscribe) {
46+
const value = new ReactiveValue(getSnapshot, onSubscribe);
47+
return () => value.current
48+
}

packages/svelte/src/reactivity/index-client.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export { SvelteURL } from './url.js';
55
export { SvelteURLSearchParams } from './url-search-params.js';
66
export { MediaQuery } from './media-query.js';
77
export { createSubscriber } from './create-subscriber.js';
8+
export { createReactiveFunction } from './create-reactive-function.js';

packages/svelte/src/reactivity/index-server.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,13 @@ export class MediaQuery {
2121
export function createSubscriber(_) {
2222
return () => {};
2323
}
24+
25+
/**
26+
* @template T
27+
* @param {() => T} getSnapshot
28+
* @param {any} __
29+
* @returns {() => T}
30+
*/
31+
export function createReactiveFunction(getSnapshot, __) {
32+
return getSnapshot
33+
}

0 commit comments

Comments
 (0)