Skip to content

Commit 3c8a4a8

Browse files
committed
add store toJSON
1 parent 3260bd7 commit 3c8a4a8

File tree

3 files changed

+81
-1
lines changed

3 files changed

+81
-1
lines changed

packages/qwik/src/core/v2/signal/v2-signal.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ export class Signal2<T = any> extends Subscriber implements ISignal2<T> {
213213
toString() {
214214
return (
215215
`[${this.constructor.name}${(this as any).$invalid$ ? ' INVALID' : ''} ${String(this.$untrackedValue$)}]` +
216-
this.$effects$?.map((e) => '\n -> ' + pad(qwikDebugToString(e[0]), ' ')).join('\n') || ''
216+
(this.$effects$?.map((e) => '\n -> ' + pad(qwikDebugToString(e[0]), ' ')).join('\n') || '')
217217
);
218218
}
219219
toJSON() {

packages/qwik/src/core/v2/signal/v2-store.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { pad, qwikDebugToString } from '../../debug';
22
import { assertTrue } from '../../error/assert';
3+
import { _wrapProp } from '../../state/signal';
34
import { tryGetInvokeContext } from '../../use/use-core';
45
import { isSerializableObject } from '../../util/types';
56
import { SERIALIZER_PROXY_UNWRAP } from '../shared/shared-serialization';
@@ -121,6 +122,18 @@ export class StoreHandler<T extends Record<string | symbol, any>> implements Pro
121122
// we will return the naked object which removes ourselves,
122123
// and that is not the intention so prevent of SERIALIZER_PROXY_UNWRAP.
123124
return undefined;
125+
} else if (p === 'toJSON') {
126+
return () => {
127+
// we need to add subscription to all properties
128+
// TODO: could this be done another way?
129+
for (const key in this.$target$) {
130+
if (isStore2(this.$target$[key])) {
131+
continue;
132+
}
133+
this.get(this.$target$, key);
134+
}
135+
return this.$target$;
136+
};
124137
}
125138
const target = this.$target$;
126139
const ctx = tryGetInvokeContext();

packages/qwik/src/core/v2/tests/use-store.spec.tsx

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,73 @@ describe.each([
466466
);
467467
});
468468

469+
it('should render value via JSON.stringify', async () => {
470+
const Stringify = component$<{
471+
data: any;
472+
style?: any;
473+
}>((props) => {
474+
return <>{JSON.stringify(props.data)}</>;
475+
});
476+
477+
const Cmp = component$(() => {
478+
const group = useStore({
479+
controls: {
480+
ctrl: {
481+
value: '',
482+
},
483+
},
484+
});
485+
486+
return (
487+
<button onClick$={() => (group.controls.ctrl.value = 'test')}>
488+
<Stringify data={group} />
489+
<Stringify data={group.controls} />
490+
<Stringify data={group.controls.ctrl} />
491+
<Stringify data={group.controls.ctrl.value} />
492+
</button>
493+
);
494+
});
495+
496+
const { vNode, document } = await render(<Cmp />, { debug });
497+
expect(vNode).toMatchVDOM(
498+
<Component>
499+
<button>
500+
<Component>
501+
<Signal>{'{"controls":{"ctrl":{"value":""}}}'}</Signal>
502+
</Component>
503+
<Component>
504+
<Signal>{'{"ctrl":{"value":""}}'}</Signal>
505+
</Component>
506+
<Component>
507+
<Signal>{'{"value":""}'}</Signal>
508+
</Component>
509+
<Component>
510+
<Signal>{'""'}</Signal>
511+
</Component>
512+
</button>
513+
</Component>
514+
);
515+
await trigger(document.body, 'button', 'click');
516+
expect(vNode).toMatchVDOM(
517+
<Component>
518+
<button>
519+
<Component>
520+
<Signal>{'{"controls":{"ctrl":{"value":"test"}}}'}</Signal>
521+
</Component>
522+
<Component>
523+
<Signal>{'{"ctrl":{"value":"test"}}'}</Signal>
524+
</Component>
525+
<Component>
526+
<Signal>{'{"value":"test"}'}</Signal>
527+
</Component>
528+
<Component>
529+
<Signal>{'"test"'}</Signal>
530+
</Component>
531+
</button>
532+
</Component>
533+
);
534+
});
535+
469536
describe('regression', () => {
470537
it('#5597 - should update value', async () => {
471538
(globalThis as any).clicks = 0;

0 commit comments

Comments
 (0)