Skip to content

Commit 2e132fc

Browse files
authored
Merge pull request #8160 from QwikDev/v2-undefined-default-effects-value
fix: serialize correctly null or undefined value for signals
2 parents 2f4ab02 + 1fc309c commit 2e132fc

File tree

14 files changed

+168
-78
lines changed

14 files changed

+168
-78
lines changed

.changeset/crazy-cities-tap.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@qwik.dev/core': patch
3+
---
4+
5+
fix: serialize correctly null or undefined value for signals

packages/qwik/src/core/reactive-primitives/cleanup.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { _PROPS_HANDLER } from '../shared/utils/constants';
1616

1717
/** Class for back reference to the EffectSubscription */
1818
export abstract class BackRef {
19-
[_EFFECT_BACK_REF]: Map<EffectProperty | string, EffectSubscription> | null = null;
19+
[_EFFECT_BACK_REF]: Map<EffectProperty | string, EffectSubscription> | undefined = undefined;
2020
}
2121

2222
export function clearAllEffects(container: Container, consumer: Consumer): void {
@@ -62,7 +62,7 @@ function clearSignal(container: Container, producer: SignalImpl, effect: EffectS
6262
}
6363

6464
if (producer instanceof WrappedSignalImpl) {
65-
producer.$hostElement$ = null;
65+
producer.$hostElement$ = undefined;
6666
clearAllEffects(container, producer);
6767
}
6868
}

packages/qwik/src/core/reactive-primitives/impl/async-computed-signal-impl.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ export class AsyncComputedSignalImpl<T>
3636
implements BackRef
3737
{
3838
$untrackedLoading$: boolean = false;
39-
$untrackedError$: Error | null = null;
39+
$untrackedError$: Error | undefined = undefined;
4040

41-
$loadingEffects$: null | Set<EffectSubscription> = null;
42-
$errorEffects$: null | Set<EffectSubscription> = null;
41+
$loadingEffects$: undefined | Set<EffectSubscription> = undefined;
42+
$errorEffects$: undefined | Set<EffectSubscription> = undefined;
4343
$destroy$: NoSerialize<() => void> | null;
4444
$promiseValue$: T | typeof NEEDS_COMPUTATION = NEEDS_COMPUTATION;
4545
private $promise$: Promise<T> | null = null;
4646

47-
[_EFFECT_BACK_REF]: Map<EffectProperty | string, EffectSubscription> | null = null;
47+
[_EFFECT_BACK_REF]: Map<EffectProperty | string, EffectSubscription> | undefined = undefined;
4848

4949
constructor(
5050
container: Container | null,
@@ -71,7 +71,7 @@ export class AsyncComputedSignalImpl<T>
7171
this.$untrackedLoading$ = value;
7272
this.$container$?.$scheduler$(
7373
ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
74-
null,
74+
undefined,
7575
this,
7676
this.$loadingEffects$
7777
);
@@ -83,20 +83,20 @@ export class AsyncComputedSignalImpl<T>
8383
}
8484

8585
/** The error that occurred when the signal was resolved. */
86-
get error(): Error | null {
86+
get error(): Error | undefined {
8787
return setupSignalValueAccess(
8888
this,
8989
() => (this.$errorEffects$ ||= new Set()),
9090
() => this.untrackedError
9191
);
9292
}
9393

94-
set untrackedError(value: Error | null) {
94+
set untrackedError(value: Error | undefined) {
9595
if (value !== this.$untrackedError$) {
9696
this.$untrackedError$ = value;
9797
this.$container$?.$scheduler$(
9898
ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
99-
null,
99+
undefined,
100100
this,
101101
this.$errorEffects$
102102
);
@@ -136,7 +136,7 @@ export class AsyncComputedSignalImpl<T>
136136
if (isPromise(untrackedValue)) {
137137
const isFirstComputation = this.$promiseValue$ === NEEDS_COMPUTATION;
138138
this.untrackedLoading = true;
139-
this.untrackedError = null;
139+
this.untrackedError = undefined;
140140

141141
if (this.$promiseValue$ !== NEEDS_COMPUTATION) {
142142
// skip cleanup after resuming
@@ -148,7 +148,7 @@ export class AsyncComputedSignalImpl<T>
148148
DEBUG && log('Promise resolved', promiseValue);
149149
this.$promiseValue$ = promiseValue;
150150
this.untrackedLoading = false;
151-
this.untrackedError = null;
151+
this.untrackedError = undefined;
152152
if (this.setValue(promiseValue)) {
153153
DEBUG && log('Scheduling effects for subscribers', this.$effects$?.size);
154154
scheduleEffects(this.$container$, this, this.$effects$);

packages/qwik/src/core/reactive-primitives/impl/computed-signal-impl.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export class ComputedSignalImpl<T, S extends QRLInternal = ComputeQRL<T>>
3434
*/
3535
$computeQrl$: S;
3636
$flags$: SignalFlags | SerializationSignalFlags;
37-
[_EFFECT_BACK_REF]: Map<EffectProperty | string, EffectSubscription> | null = null;
37+
[_EFFECT_BACK_REF]: Map<EffectProperty | string, EffectSubscription> | undefined = undefined;
3838

3939
constructor(
4040
container: Container | null,
@@ -55,7 +55,7 @@ export class ComputedSignalImpl<T, S extends QRLInternal = ComputeQRL<T>>
5555
this.$flags$ |= SignalFlags.INVALID;
5656
this.$container$?.$scheduler$(
5757
ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
58-
null,
58+
undefined,
5959
this,
6060
this.$effects$
6161
);

packages/qwik/src/core/reactive-primitives/impl/signal-impl.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export class SignalImpl<T = any> implements Signal<T> {
2323
$untrackedValue$: T;
2424

2525
/** Store a list of effects which are dependent on this signal. */
26-
$effects$: null | Set<EffectSubscription> = null;
26+
$effects$: undefined | Set<EffectSubscription> = undefined;
2727
$container$: Container | null = null;
2828
$wrappedSignal$: WrappedSignalImpl<T> | null = null;
2929

@@ -40,7 +40,7 @@ export class SignalImpl<T = any> implements Signal<T> {
4040
force() {
4141
this.$container$?.$scheduler$(
4242
ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
43-
null,
43+
undefined,
4444
this,
4545
this.$effects$
4646
);
@@ -70,7 +70,7 @@ export class SignalImpl<T = any> implements Signal<T> {
7070
this.$untrackedValue$ = value;
7171
this.$container$?.$scheduler$(
7272
ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
73-
null,
73+
undefined,
7474
this,
7575
this.$effects$
7676
);

packages/qwik/src/core/reactive-primitives/impl/store.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export const getOrCreateStore = <T extends object>(
9696
};
9797

9898
export class StoreHandler implements ProxyHandler<StoreTarget> {
99-
$effects$: null | Map<string | symbol, Set<EffectSubscription>> = null;
99+
$effects$: undefined | Map<string | symbol, Set<EffectSubscription>> = undefined;
100100

101101
constructor(
102102
public $flags$: StoreFlags,
@@ -111,7 +111,7 @@ export class StoreHandler implements ProxyHandler<StoreTarget> {
111111
const target = getStoreTarget(this)!;
112112
this.$container$?.$scheduler$(
113113
ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
114-
null,
114+
undefined,
115115
this,
116116
getEffects(target, prop, this.$effects$)
117117
);
@@ -201,7 +201,7 @@ export class StoreHandler implements ProxyHandler<StoreTarget> {
201201
// Changing the length property will trigger effects.
202202
this.$container$?.$scheduler$(
203203
ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
204-
null,
204+
undefined,
205205
this,
206206
getEffects(target, prop, this.$effects$)
207207
);
@@ -294,7 +294,7 @@ function setNewValueAndTriggerEffects<T extends Record<string | symbol, any>>(
294294
if (effects) {
295295
currentStore.$container$?.$scheduler$(
296296
ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
297-
null,
297+
undefined,
298298
currentStore,
299299
effects
300300
);
@@ -304,7 +304,7 @@ function setNewValueAndTriggerEffects<T extends Record<string | symbol, any>>(
304304
function getEffects<T extends Record<string | symbol, any>>(
305305
target: T,
306306
prop: string | symbol,
307-
storeEffects: Map<string | symbol, Set<EffectSubscription>> | null
307+
storeEffects: Map<string | symbol, Set<EffectSubscription>> | undefined
308308
) {
309309
let effectsToTrigger: Set<EffectSubscription> | undefined;
310310

@@ -328,5 +328,5 @@ function getEffects<T extends Record<string | symbol, any>>(
328328
effectsToTrigger!.add(effect);
329329
}
330330
}
331-
return effectsToTrigger || null;
331+
return effectsToTrigger;
332332
}

packages/qwik/src/core/reactive-primitives/impl/wrapped-signal-impl.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ export class WrappedSignalImpl<T> extends SignalImpl<T> implements BackRef {
2222
$funcStr$: string | null;
2323

2424
$flags$: AllSignalFlags;
25-
$hostElement$: HostElement | null = null;
26-
[_EFFECT_BACK_REF]: Map<EffectProperty | string, EffectSubscription> | null = null;
25+
$hostElement$: HostElement | undefined = undefined;
26+
[_EFFECT_BACK_REF]: Map<EffectProperty | string, EffectSubscription> | undefined = undefined;
2727

2828
constructor(
2929
container: Container | null,

packages/qwik/src/core/reactive-primitives/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export const addQrlToSerializationCtx = (
8888
export const scheduleEffects = (
8989
container: Container | null,
9090
signal: SignalImpl | StoreTarget,
91-
effects: Set<EffectSubscription> | null
91+
effects: Set<EffectSubscription> | undefined
9292
) => {
9393
const isBrowser = !isServerPlatform();
9494
if (effects) {

packages/qwik/src/core/shared/jsx/props-proxy.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export function createPropsProxy(owner: JSXNodeImpl): Props {
1717
return new Proxy<any>({}, new PropsProxyHandler(owner));
1818
}
1919
export class PropsProxyHandler implements ProxyHandler<any> {
20-
$effects$: null | Map<string | symbol, Set<EffectSubscription>> = null;
20+
$effects$: undefined | Map<string | symbol, Set<EffectSubscription>> = undefined;
2121
$container$: Container | null = null;
2222

2323
constructor(public owner: JSXNodeImpl) {}
@@ -176,19 +176,19 @@ export const triggerPropsProxyEffect = (propsProxy: PropsProxyHandler, prop: str
176176
if (effects) {
177177
propsProxy.$container$?.$scheduler$(
178178
ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
179-
null,
179+
undefined,
180180
propsProxy,
181181
effects
182182
);
183183
}
184184
};
185185

186186
function getEffects(
187-
effects: Map<string | symbol, Set<EffectSubscription>> | null,
187+
effects: Map<string | symbol, Set<EffectSubscription>> | undefined,
188188
prop: string | symbol
189189
) {
190190
// TODO: Handle STORE_ALL_PROPS
191-
return effects?.get(prop) || null;
191+
return effects?.get(prop);
192192
}
193193

194194
/**

packages/qwik/src/core/shared/scheduler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,9 @@ export const createScheduler = (
221221
*/
222222
function schedule(
223223
type: ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
224-
host: HostElement | null,
224+
host: HostElement | undefined,
225225
target: Signal<unknown> | StoreTarget,
226-
effects: Set<EffectSubscription> | null
226+
effects: Set<EffectSubscription> | undefined
227227
): Chore<ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS>;
228228
function schedule(
229229
type: ChoreType.TASK | ChoreType.VISIBLE,

0 commit comments

Comments
 (0)