easy-signal 3.2.2 → 3.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/reactiveSignal.d.ts +4 -4
- package/dist/reactiveSignal.js +20 -9
- package/dist/reactiveSignal.js.map +1 -1
- package/package.json +1 -1
- package/src/reactiveSignal.ts +29 -13
package/dist/reactiveSignal.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export interface ReactiveSignal<T> extends ComputedSignal<T> {
|
|
|
28
28
|
*/
|
|
29
29
|
export interface ComputedSignal<T> {
|
|
30
30
|
(): T;
|
|
31
|
-
subscribe: (subscriber: ReactiveSignalSubscriber<T>,
|
|
31
|
+
subscribe: (subscriber: ReactiveSignalSubscriber<T>, when?: Timing | null, deferInitial?: boolean) => Unsubscribe;
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* A Signal Subscriber is a function that will be called whenever the signal's value changes. The subscriber will be
|
|
@@ -76,7 +76,7 @@ export declare function reactiveSignal<T>(value: T, options?: SignalOptions<T>):
|
|
|
76
76
|
*
|
|
77
77
|
* The returned function can be called to unsubscribe from the Signal.
|
|
78
78
|
*/
|
|
79
|
-
export declare function subscribe<T>(signal: ReactiveSignal<T>,
|
|
79
|
+
export declare function subscribe<T>(signal: ReactiveSignal<T>, changeHandler: ReactiveSignalSubscriber<T>, timing?: Timing | null, deferInitial?: boolean): Unsubscribe;
|
|
80
80
|
/**
|
|
81
81
|
* Get notified when a Signal's subscribers changes from none to some or some to none.
|
|
82
82
|
*/
|
|
@@ -91,7 +91,7 @@ export declare function onSubscriptionChange(signal: ReactiveSignal<any>, onChan
|
|
|
91
91
|
* The optional second argument, `timing`, can be used to specify when the function should be called. The default is
|
|
92
92
|
* undefined which executes the function immediately.
|
|
93
93
|
*/
|
|
94
|
-
export declare function observe(fn: ReactiveSignalObserver, timing?: Timing): Unsubscribe;
|
|
94
|
+
export declare function observe(fn: ReactiveSignalObserver, timing?: Timing, deferInitial?: boolean): Unsubscribe;
|
|
95
95
|
/**
|
|
96
96
|
* Create a Computed Signal which is a signal that is the result of a function that depends on other signals. The
|
|
97
97
|
* function is called immediately whenever the computed signal is accessed if there are no subscribers, or whenever its
|
|
@@ -101,4 +101,4 @@ export declare function observe(fn: ReactiveSignalObserver, timing?: Timing): Un
|
|
|
101
101
|
* undefined which executes the function immediately after any change to any signal it relies on. This can
|
|
102
102
|
* prevent unnecessary updates if the function is expensive to run.
|
|
103
103
|
*/
|
|
104
|
-
export declare function computedSignal<T>(fn: ReactiveSignalUpdater<T>, when?: Timing): ComputedSignal<T>;
|
|
104
|
+
export declare function computedSignal<T>(fn: ReactiveSignalUpdater<T>, when?: Timing, deferInitial?: boolean): ComputedSignal<T>;
|
package/dist/reactiveSignal.js
CHANGED
|
@@ -10,6 +10,7 @@ export const Timing = {
|
|
|
10
10
|
},
|
|
11
11
|
};
|
|
12
12
|
let context = null;
|
|
13
|
+
let getHasSubscribers = false;
|
|
13
14
|
// A map to keep track of listeners to subscription changes
|
|
14
15
|
const onSubscriptionChanges = new WeakMap();
|
|
15
16
|
/**
|
|
@@ -28,6 +29,8 @@ export function reactiveSignal(value, options) {
|
|
|
28
29
|
const signal = ((newValue, set) => {
|
|
29
30
|
// If no new value is provided, subscribe the current run to this signal and return the current value
|
|
30
31
|
if (!set && newValue === undefined) {
|
|
32
|
+
if (getHasSubscribers)
|
|
33
|
+
return subscribers.size > 0;
|
|
31
34
|
// If there is a context (an observer is running), add the observer's subscriber to the signal
|
|
32
35
|
if (context) {
|
|
33
36
|
const { subscriber: run, unsubscribes } = context;
|
|
@@ -84,20 +87,23 @@ export function reactiveSignal(value, options) {
|
|
|
84
87
|
*
|
|
85
88
|
* The returned function can be called to unsubscribe from the Signal.
|
|
86
89
|
*/
|
|
87
|
-
export function subscribe(signal,
|
|
90
|
+
export function subscribe(signal, changeHandler, timing = Timing.Tick, deferInitial = false) {
|
|
91
|
+
let subscriber;
|
|
88
92
|
if (timing) {
|
|
89
93
|
let queued = false;
|
|
90
|
-
const subFn = subscriber;
|
|
91
94
|
subscriber = () => {
|
|
92
95
|
if (!queued) {
|
|
93
96
|
queued = true;
|
|
94
97
|
timing(() => {
|
|
95
98
|
queued = false;
|
|
96
|
-
|
|
99
|
+
changeHandler(signal());
|
|
97
100
|
});
|
|
98
101
|
}
|
|
99
102
|
};
|
|
100
103
|
}
|
|
104
|
+
else {
|
|
105
|
+
subscriber = changeHandler;
|
|
106
|
+
}
|
|
101
107
|
// Set the current context so we can get the unsubscribe
|
|
102
108
|
context = { prior: context, subscriber, unsubscribes: new Set() };
|
|
103
109
|
// Get the current value of the signal
|
|
@@ -106,8 +112,8 @@ export function subscribe(signal, subscriber, timing = Timing.Tick) {
|
|
|
106
112
|
const unsubscribe = context.unsubscribes.values().next().value;
|
|
107
113
|
// Clear the current context
|
|
108
114
|
context = context.prior;
|
|
109
|
-
// Call the
|
|
110
|
-
subscriber(value);
|
|
115
|
+
// Call the changeHandler with the current value immediately, regardless of timing, unless deferred
|
|
116
|
+
deferInitial ? subscriber(value) : changeHandler(value);
|
|
111
117
|
// Return the unsubscribe function
|
|
112
118
|
return unsubscribe;
|
|
113
119
|
}
|
|
@@ -122,6 +128,11 @@ export function onSubscriptionChange(signal, onChange) {
|
|
|
122
128
|
onSubscriptionChanges.set(signal, (onChanges = new Set()));
|
|
123
129
|
// Add the onChange function to the set
|
|
124
130
|
onChanges.add(onChange);
|
|
131
|
+
// Pretty little hack to get the current value of hasSubscribers
|
|
132
|
+
getHasSubscribers = true;
|
|
133
|
+
const hasSubscribers = signal();
|
|
134
|
+
getHasSubscribers = false;
|
|
135
|
+
onChange(hasSubscribers);
|
|
125
136
|
// Return a function that removes the onChange function from the set
|
|
126
137
|
return () => {
|
|
127
138
|
onChanges.delete(onChange);
|
|
@@ -137,7 +148,7 @@ export function onSubscriptionChange(signal, onChange) {
|
|
|
137
148
|
* The optional second argument, `timing`, can be used to specify when the function should be called. The default is
|
|
138
149
|
* undefined which executes the function immediately.
|
|
139
150
|
*/
|
|
140
|
-
export function observe(fn, timing) {
|
|
151
|
+
export function observe(fn, timing, deferInitial) {
|
|
141
152
|
let dirty = true;
|
|
142
153
|
let unsubscribes = new Set();
|
|
143
154
|
// Subscribe to all the signals that are called when the effect is run
|
|
@@ -169,7 +180,7 @@ export function observe(fn, timing) {
|
|
|
169
180
|
context = context.prior;
|
|
170
181
|
};
|
|
171
182
|
// Call immediately (or on the next timing)
|
|
172
|
-
if (timing)
|
|
183
|
+
if (deferInitial && timing)
|
|
173
184
|
timing(() => onChange());
|
|
174
185
|
else
|
|
175
186
|
onChange();
|
|
@@ -185,7 +196,7 @@ export function observe(fn, timing) {
|
|
|
185
196
|
* undefined which executes the function immediately after any change to any signal it relies on. This can
|
|
186
197
|
* prevent unnecessary updates if the function is expensive to run.
|
|
187
198
|
*/
|
|
188
|
-
export function computedSignal(fn, when) {
|
|
199
|
+
export function computedSignal(fn, when, deferInitial) {
|
|
189
200
|
// Create the signal
|
|
190
201
|
const signal = reactiveSignal(undefined);
|
|
191
202
|
// Store the unsubscribe function from the observer. We will only observe the function when there are subscribers to
|
|
@@ -196,7 +207,7 @@ export function computedSignal(fn, when) {
|
|
|
196
207
|
// If there are subscribers, start observing the function
|
|
197
208
|
if (hasSubscribers) {
|
|
198
209
|
if (!unsubscribe)
|
|
199
|
-
unsubscribe = observe(() => signal(fn), when);
|
|
210
|
+
unsubscribe = observe(() => signal(fn), when, deferInitial);
|
|
200
211
|
}
|
|
201
212
|
else if (unsubscribe) {
|
|
202
213
|
// If there are no subscribers, stop observing the function
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reactiveSignal.js","sourceRoot":"","sources":["../src/reactiveSignal.ts"],"names":[],"mappings":"AASA,uEAAuE;AACvE,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,0DAA0D;IAC1D,IAAI,EAAE,CAAC,EAAc,EAAE,EAAE;QACvB,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC;IACD,mDAAmD;IACnD,cAAc,EAAE,CAAC,EAAc,EAAE,EAAE;QAChC,UAAkB,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC;IAChD,CAAC;CACF,CAAC;AAIF,IAAI,OAAO,GAAmB,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"reactiveSignal.js","sourceRoot":"","sources":["../src/reactiveSignal.ts"],"names":[],"mappings":"AASA,uEAAuE;AACvE,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,0DAA0D;IAC1D,IAAI,EAAE,CAAC,EAAc,EAAE,EAAE;QACvB,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC;IACD,mDAAmD;IACnD,cAAc,EAAE,CAAC,EAAc,EAAE,EAAE;QAChC,UAAkB,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC;IAChD,CAAC;CACF,CAAC;AAIF,IAAI,OAAO,GAAmB,IAAI,CAAC;AACnC,IAAI,iBAAiB,GAAG,KAAK,CAAC;AAE9B,2DAA2D;AAC3D,MAAM,qBAAqB,GAAG,IAAI,OAAO,EAAgD,CAAC;AA4D1F;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAI,KAAQ,EAAE,OAA0B;IACpE,qCAAqC;IACrC,MAAM,WAAW,GAAG,IAAI,GAAG,EAA4C,CAAC;IAExE,mHAAmH;IACnH,gFAAgF;IAChF,MAAM,MAAM,GAAG,CAAC,CAAC,QAAuC,EAAE,GAAa,EAAE,EAAE;QACzE,qGAAqG;QACrG,IAAI,CAAC,GAAG,IAAI,QAAQ,KAAK,SAAS,EAAE;YAClC,IAAI,iBAAiB;gBAAE,OAAO,WAAW,CAAC,IAAI,GAAG,CAAC,CAAC;YAEnD,8FAA8F;YAC9F,IAAI,OAAO,EAAE;gBACX,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;gBAClD,IAAI,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAEvC,qDAAqD;gBACrD,IAAI,CAAC,WAAW,EAAE;oBAChB,kCAAkC;oBAClC,WAAW,GAAG,GAAG,EAAE;wBACjB,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;wBAExB,oEAAoE;wBACpE,IAAI,WAAW,CAAC,IAAI,KAAK,CAAC,EAAE;4BAC1B,MAAM,SAAS,GAAG,qBAAqB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;4BACpD,IAAI,SAAS;gCAAE,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;yBAC/D;oBACH,CAAC,CAAC;oBAEF,2DAA2D;oBAC3D,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;oBAElC,oGAAoG;oBACpG,IAAI,WAAW,CAAC,IAAI,KAAK,CAAC,EAAE;wBAC1B,MAAM,SAAS,GAAG,qBAAqB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;wBACpD,IAAI,SAAS;4BAAE,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;qBAC9D;iBACF;gBAED,yDAAyD;gBACzD,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;aAC/B;YAED,2BAA2B;YAC3B,OAAO,KAAK,CAAC;SACd;QAED,gFAAgF;QAChF,IAAI,CAAC,GAAG,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE;YAC1C,QAAQ,GAAI,QAAqC,CAAC,KAAK,CAAC,CAAC;SAC1D;QAED,kHAAkH;QAClH,mCAAmC;QACnC,IAAI,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAM,EAAE,QAAa,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,EAAE;YACjF,KAAK,GAAG,QAAa,CAAC;YACtB,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAM,CAAC,CAAC,CAAC;SAC9C;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAsB,CAAC;IAExB,MAAM,CAAC,SAAS,GAAG,CAAC,UAAuC,EAAE,SAAwB,MAAM,CAAC,IAAI,EAAE,EAAE,CAClG,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;IAExC,6BAA6B;IAC7B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CACvB,MAAyB,EACzB,aAA0C,EAC1C,SAAwB,MAAM,CAAC,IAAI,EACnC,YAAY,GAAG,KAAK;IAEpB,IAAI,UAAuC,CAAC;IAC5C,IAAI,MAAM,EAAE;QACV,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,UAAU,GAAG,GAAG,EAAE;YAChB,IAAI,CAAC,MAAM,EAAE;gBACX,MAAM,GAAG,IAAI,CAAC;gBACd,MAAM,CAAC,GAAG,EAAE;oBACV,MAAM,GAAG,KAAK,CAAC;oBACf,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;gBAC1B,CAAC,CAAC,CAAC;aACJ;QACH,CAAC,CAAC;KACH;SAAM;QACL,UAAU,GAAG,aAAa,CAAC;KAC5B;IAED,wDAAwD;IACxD,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;IAElE,sCAAsC;IACtC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC;IAEvB,kDAAkD;IAClD,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;IAE/D,4BAA4B;IAC5B,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC;IAExB,mGAAmG;IACnG,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAExD,kCAAkC;IAClC,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAA2B,EAC3B,QAA2C;IAE3C,mDAAmD;IACnD,IAAI,SAAS,GAAG,qBAAqB,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC;IAEnD,uDAAuD;IACvD,IAAI,CAAC,SAAS;QAAE,qBAAqB,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;IAE3E,uCAAuC;IACvC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAExB,gEAAgE;IAChE,iBAAiB,GAAG,IAAI,CAAC;IACzB,MAAM,cAAc,GAAG,MAAM,EAAE,CAAC;IAChC,iBAAiB,GAAG,KAAK,CAAC;IAC1B,QAAQ,CAAC,cAAc,CAAC,CAAC;IAEzB,oEAAoE;IACpE,OAAO,GAAG,EAAE;QACV,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,OAAO,CAAC,EAA0B,EAAE,MAAe,EAAE,YAAsB;IACzF,IAAI,KAAK,GAAG,IAAI,CAAC;IACjB,IAAI,YAAY,GAAG,IAAI,GAAG,EAAe,CAAC;IAE1C,sEAAsE;IACtE,MAAM,UAAU,GAAG,GAAG,EAAE;QACtB,IAAI,KAAK;YAAE,OAAO;QAClB,KAAK,GAAG,IAAI,CAAC;QACb,IAAI,MAAM;YAAE,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;;YAChC,QAAQ,EAAE,CAAC;IAClB,CAAC,CAAC;IAEF,6FAA6F;IAC7F,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,KAAK,GAAG,KAAK,CAAC;QAEd,iCAAiC;QACjC,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;QAElE,iGAAiG;QACjG,EAAE,EAAE,CAAC;QAEL,8EAA8E;QAC9E,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAE1D,6DAA6D;QAC7D,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAE/B,2BAA2B;QAC3B,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;QAEpC,oBAAoB;QACpB,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC;IAC1B,CAAC,CAAC;IAEF,2CAA2C;IAC3C,IAAI,YAAY,IAAI,MAAM;QAAE,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;;QAChD,QAAQ,EAAE,CAAC;IAEhB,kGAAkG;IAClG,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAC5B,EAA4B,EAC5B,IAAa,EACb,YAAsB;IAEtB,oBAAoB;IACpB,MAAM,MAAM,GAAG,cAAc,CAAI,SAAc,CAAC,CAAC;IAEjD,oHAAoH;IACpH,wBAAwB;IACxB,IAAI,WAAW,GAAuB,IAAI,CAAC;IAE3C,6FAA6F;IAC7F,oBAAoB,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE;QAC5C,yDAAyD;QACzD,IAAI,cAAc,EAAE;YAClB,IAAI,CAAC,WAAW;gBAAE,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;SAC/E;aAAM,IAAI,WAAW,EAAE;YACtB,2DAA2D;YAC3D,WAAW,EAAE,CAAC;YACd,WAAW,GAAG,IAAI,CAAC;SACpB;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,QAAQ,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IAEtC,oBAAoB;IACpB,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/package.json
CHANGED
package/src/reactiveSignal.ts
CHANGED
|
@@ -22,6 +22,7 @@ export const Timing = {
|
|
|
22
22
|
// The context for the current run and its unsubscribes
|
|
23
23
|
type Context = { prior: Context | null; subscriber: ReactiveSignalSubscriber<any>; unsubscribes: Set<Unsubscribe> };
|
|
24
24
|
let context: Context | null = null;
|
|
25
|
+
let getHasSubscribers = false;
|
|
25
26
|
|
|
26
27
|
// A map to keep track of listeners to subscription changes
|
|
27
28
|
const onSubscriptionChanges = new WeakMap<ReactiveSignal<any>, Set<SubscriptionChange>>();
|
|
@@ -48,7 +49,7 @@ export interface ReactiveSignal<T> extends ComputedSignal<T> {
|
|
|
48
49
|
*/
|
|
49
50
|
export interface ComputedSignal<T> {
|
|
50
51
|
(): T;
|
|
51
|
-
subscribe: (subscriber: ReactiveSignalSubscriber<T>,
|
|
52
|
+
subscribe: (subscriber: ReactiveSignalSubscriber<T>, when?: Timing | null, deferInitial?: boolean) => Unsubscribe;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
/**
|
|
@@ -101,6 +102,8 @@ export function reactiveSignal<T>(value: T, options?: SignalOptions<T>): Reactiv
|
|
|
101
102
|
const signal = ((newValue?: T | ReactiveSignalUpdater<T>, set?: boolean) => {
|
|
102
103
|
// If no new value is provided, subscribe the current run to this signal and return the current value
|
|
103
104
|
if (!set && newValue === undefined) {
|
|
105
|
+
if (getHasSubscribers) return subscribers.size > 0;
|
|
106
|
+
|
|
104
107
|
// If there is a context (an observer is running), add the observer's subscriber to the signal
|
|
105
108
|
if (context) {
|
|
106
109
|
const { subscriber: run, unsubscribes } = context;
|
|
@@ -169,21 +172,24 @@ export function reactiveSignal<T>(value: T, options?: SignalOptions<T>): Reactiv
|
|
|
169
172
|
*/
|
|
170
173
|
export function subscribe<T>(
|
|
171
174
|
signal: ReactiveSignal<T>,
|
|
172
|
-
|
|
173
|
-
timing: Timing | null = Timing.Tick
|
|
175
|
+
changeHandler: ReactiveSignalSubscriber<T>,
|
|
176
|
+
timing: Timing | null = Timing.Tick,
|
|
177
|
+
deferInitial = false
|
|
174
178
|
): Unsubscribe {
|
|
179
|
+
let subscriber: ReactiveSignalSubscriber<T>;
|
|
175
180
|
if (timing) {
|
|
176
181
|
let queued = false;
|
|
177
|
-
const subFn = subscriber;
|
|
178
182
|
subscriber = () => {
|
|
179
183
|
if (!queued) {
|
|
180
184
|
queued = true;
|
|
181
185
|
timing(() => {
|
|
182
186
|
queued = false;
|
|
183
|
-
|
|
187
|
+
changeHandler(signal());
|
|
184
188
|
});
|
|
185
189
|
}
|
|
186
190
|
};
|
|
191
|
+
} else {
|
|
192
|
+
subscriber = changeHandler;
|
|
187
193
|
}
|
|
188
194
|
|
|
189
195
|
// Set the current context so we can get the unsubscribe
|
|
@@ -198,8 +204,8 @@ export function subscribe<T>(
|
|
|
198
204
|
// Clear the current context
|
|
199
205
|
context = context.prior;
|
|
200
206
|
|
|
201
|
-
// Call the
|
|
202
|
-
subscriber(value);
|
|
207
|
+
// Call the changeHandler with the current value immediately, regardless of timing, unless deferred
|
|
208
|
+
deferInitial ? subscriber(value) : changeHandler(value);
|
|
203
209
|
|
|
204
210
|
// Return the unsubscribe function
|
|
205
211
|
return unsubscribe;
|
|
@@ -213,7 +219,7 @@ export function onSubscriptionChange(
|
|
|
213
219
|
onChange: (hasSubscribers: boolean) => void
|
|
214
220
|
): Unsubscribe {
|
|
215
221
|
// Get the set of onChange functions for the signal
|
|
216
|
-
let onChanges = onSubscriptionChanges.get(signal)
|
|
222
|
+
let onChanges = onSubscriptionChanges.get(signal)!;
|
|
217
223
|
|
|
218
224
|
// If there is no set, create one and add it to the map
|
|
219
225
|
if (!onChanges) onSubscriptionChanges.set(signal, (onChanges = new Set()));
|
|
@@ -221,9 +227,15 @@ export function onSubscriptionChange(
|
|
|
221
227
|
// Add the onChange function to the set
|
|
222
228
|
onChanges.add(onChange);
|
|
223
229
|
|
|
230
|
+
// Pretty little hack to get the current value of hasSubscribers
|
|
231
|
+
getHasSubscribers = true;
|
|
232
|
+
const hasSubscribers = signal();
|
|
233
|
+
getHasSubscribers = false;
|
|
234
|
+
onChange(hasSubscribers);
|
|
235
|
+
|
|
224
236
|
// Return a function that removes the onChange function from the set
|
|
225
237
|
return () => {
|
|
226
|
-
onChanges
|
|
238
|
+
onChanges.delete(onChange);
|
|
227
239
|
};
|
|
228
240
|
}
|
|
229
241
|
|
|
@@ -237,7 +249,7 @@ export function onSubscriptionChange(
|
|
|
237
249
|
* The optional second argument, `timing`, can be used to specify when the function should be called. The default is
|
|
238
250
|
* undefined which executes the function immediately.
|
|
239
251
|
*/
|
|
240
|
-
export function observe(fn: ReactiveSignalObserver, timing?: Timing): Unsubscribe {
|
|
252
|
+
export function observe(fn: ReactiveSignalObserver, timing?: Timing, deferInitial?: boolean): Unsubscribe {
|
|
241
253
|
let dirty = true;
|
|
242
254
|
let unsubscribes = new Set<Unsubscribe>();
|
|
243
255
|
|
|
@@ -274,7 +286,7 @@ export function observe(fn: ReactiveSignalObserver, timing?: Timing): Unsubscrib
|
|
|
274
286
|
};
|
|
275
287
|
|
|
276
288
|
// Call immediately (or on the next timing)
|
|
277
|
-
if (timing) timing(() => onChange());
|
|
289
|
+
if (deferInitial && timing) timing(() => onChange());
|
|
278
290
|
else onChange();
|
|
279
291
|
|
|
280
292
|
// Return a function that unsubscribes from all the signals that are called when the effect is run
|
|
@@ -290,7 +302,11 @@ export function observe(fn: ReactiveSignalObserver, timing?: Timing): Unsubscrib
|
|
|
290
302
|
* undefined which executes the function immediately after any change to any signal it relies on. This can
|
|
291
303
|
* prevent unnecessary updates if the function is expensive to run.
|
|
292
304
|
*/
|
|
293
|
-
export function computedSignal<T>(
|
|
305
|
+
export function computedSignal<T>(
|
|
306
|
+
fn: ReactiveSignalUpdater<T>,
|
|
307
|
+
when?: Timing,
|
|
308
|
+
deferInitial?: boolean
|
|
309
|
+
): ComputedSignal<T> {
|
|
294
310
|
// Create the signal
|
|
295
311
|
const signal = reactiveSignal<T>(undefined as T);
|
|
296
312
|
|
|
@@ -302,7 +318,7 @@ export function computedSignal<T>(fn: ReactiveSignalUpdater<T>, when?: Timing):
|
|
|
302
318
|
onSubscriptionChange(signal, hasSubscribers => {
|
|
303
319
|
// If there are subscribers, start observing the function
|
|
304
320
|
if (hasSubscribers) {
|
|
305
|
-
if (!unsubscribe) unsubscribe = observe(() => signal(fn), when);
|
|
321
|
+
if (!unsubscribe) unsubscribe = observe(() => signal(fn), when, deferInitial);
|
|
306
322
|
} else if (unsubscribe) {
|
|
307
323
|
// If there are no subscribers, stop observing the function
|
|
308
324
|
unsubscribe();
|