Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/solid-olives-know.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@qwik.dev/core': patch
---

fix: reactivity after spreading props
2 changes: 2 additions & 0 deletions packages/qwik/src/core/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ export {
_jsxS,
_jsxSorted,
_jsxSplit,
_getVarProps,
_getConstProps,
} from './shared/jsx/jsx-runtime';
export { _fnSignal } from './shared/qrl/inlined-fn';
export { _SharedContainer } from './shared/shared-container';
Expand Down
13 changes: 9 additions & 4 deletions packages/qwik/src/core/qwik.core.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,12 @@ export type FunctionComponent<P = unknown> = {
renderFn(props: P, key: string | null, flags: number, dev?: DevJSX): JSXOutput;
}['renderFn'];

// Warning: (ae-forgotten-export) The symbol "PropsProxy" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts
//
// @internal (undocumented)
export const _getConstProps: <T, JSX>(props: PropsProxy | Record<string, unknown> | null | undefined) => Props | null;

// @internal (undocumented)
export const _getContextContainer: () => ClientContainer | undefined;

Expand All @@ -367,6 +373,9 @@ export const getPlatform: () => CorePlatform;
// @internal (undocumented)
export function _getQContainerElement(element: Element | _VNode): Element | null;

// @internal (undocumented)
export const _getVarProps: <T, JSX>(props: PropsProxy | Record<string, unknown> | null | undefined) => Props | null;

// @public
function h<TYPE extends string | FunctionComponent<PROPS>, PROPS extends {} = {}>(type: TYPE, props?: PROPS | null, ...children: any[]): JSXNode<TYPE>;
export { h as createElement }
Expand Down Expand Up @@ -447,8 +456,6 @@ export function _isStringifiable(value: unknown): value is _Stringifiable;
// @internal (undocumented)
export const _isTask: (value: any) => value is Task;

// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts
//
// @public
const jsx: <T extends string | FunctionComponent<any>>(type: T, props: T extends FunctionComponent<infer PROPS> ? PROPS : Props, key?: string | number | null) => JSXNode<T>;
export { jsx }
Expand Down Expand Up @@ -892,8 +899,6 @@ export interface ResourceResolved<T> {
// @public (undocumented)
export type ResourceReturn<T> = ResourcePending<T> | ResourceResolved<T> | ResourceRejected<T>;

// Warning: (ae-forgotten-export) The symbol "PropsProxy" needs to be exported by the entry point index.d.ts
//
// @internal (undocumented)
export const _restProps: (props: PropsProxy, omit: string[], target?: Props) => Props;

Expand Down
24 changes: 24 additions & 0 deletions packages/qwik/src/core/shared/jsx/jsx-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,4 +427,28 @@ export const directGetPropsProxyProp = <T, JSX>(jsx: JSXNodeInternal<JSX>, prop:
) as T;
};

/** @internal */
export const _getVarProps = <T, JSX>(
props: PropsProxy | Record<string, unknown> | null | undefined
): Props | null => {
if (!props) {
return null;
}
return _VAR_PROPS in props
? 'children' in props
? { ...props[_VAR_PROPS], children: props.children }
: props[_VAR_PROPS]
: props;
};

/** @internal */
export const _getConstProps = <T, JSX>(
props: PropsProxy | Record<string, unknown> | null | undefined
): Props | null => {
if (!props) {
return null;
}
return _CONST_PROPS in props ? props[_CONST_PROPS] : null;
};

export { jsx as jsxs };
12 changes: 6 additions & 6 deletions packages/qwik/src/core/tests/attributes.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -423,11 +423,11 @@ describe.each([

expect(vNode).toMatchVDOM(
<Component ssr-required>
<Fragment ssr-required>
<Component ssr-required>
<Fragment>
<Component>
<button data-selected id="button-0"></button>
</Component>
<Component ssr-required>
<Component>
<button id="button-1"></button>
</Component>
</Fragment>
Expand All @@ -438,11 +438,11 @@ describe.each([

expect(vNode).toMatchVDOM(
<Component ssr-required>
<Fragment ssr-required>
<Component ssr-required>
<Fragment>
<Component>
<button id="button-0"></button>
</Component>
<Component ssr-required>
<Component>
<button data-selected id="button-1"></button>
</Component>
</Fragment>
Expand Down
12 changes: 12 additions & 0 deletions packages/qwik/src/core/tests/component.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2365,6 +2365,18 @@ describe.each([
expect(document.body.innerHTML).toContain('I am the innerHTML content!');
});

it('should not throw when props are null', async () => {
const Child = component$((props: any) => {
props = (globalThis as any).stuff ? (globalThis as any).foo : (globalThis as any).bar;
return <div {...props} />;
});
const Cmp = component$(() => {
return <Child />;
});
const { document } = await render(<Cmp />, { debug });
await expect(document.querySelector('div')).toMatchDOM(<div />);
});

describe('regression', () => {
it('#3643', async () => {
const Issue3643 = component$(() => {
Expand Down
42 changes: 42 additions & 0 deletions packages/qwik/src/core/tests/use-task.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
Fragment as Component,
Fragment,
Fragment as Signal,
Slot,
component$,
isServer,
useSignal,
Expand Down Expand Up @@ -323,6 +324,47 @@ describe.each([
'Child of "A" (2)', // toggle
]);
});

it('should not rerun on track if the value is not a signal', async () => {
(globalThis as any).counter = 0;
const OtpBase = component$((props: any) => {
useTask$(({ track }) => {
track(() => props.disabled);
(globalThis as any).counter++;
});

return (
<div>
<Slot />
</div>
);
});

const Cmp = component$(() => {
const isDisabled = useSignal(false);

const OtpRoot = (props: any) => {
return <OtpBase {...props}>{props.children}</OtpBase>;
};
return (
<>
<OtpRoot disabled={isDisabled.value} />

<button type="button" onClick$={() => (isDisabled.value = !isDisabled.value)}>
Disable OTP
</button>
</>
);
});

const { document } = await render(<Cmp />, { debug });
await trigger(document.body, 'button', 'click');
await trigger(document.body, 'button', 'click');
await trigger(document.body, 'button', 'click');
await trigger(document.body, 'button', 'click');
expect((globalThis as any).counter).toBe(5);
(globalThis as any).counter = undefined;
});
});
describe('queue', () => {
it('should execute dependant tasks', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ export const Foo = component$((props) => {
============================= test.js ==

import { _jsxSorted } from "@qwik.dev/core";
import { _getVarProps } from "@qwik.dev/core";
import { _getConstProps } from "@qwik.dev/core";
import { _jsxSplit } from "@qwik.dev/core";
import { componentQrl } from "@qwik.dev/core";
import { qrl } from "@qwik.dev/core";
Expand All @@ -59,16 +61,16 @@ export const Lightweight = (props)=>{
return /*#__PURE__*/ _jsxSorted("div", null, null, /*#__PURE__*/ _jsxSorted(_Fragment, null, null, [
/*#__PURE__*/ _jsxSorted("div", null, null, null, 3, null),
/*#__PURE__*/ _jsxSplit("button", {
...props
}, null, null, 0, null)
..._getVarProps(props)
}, _getConstProps(props), null, 0, null)
], 1, "u6_0"), 1, "u6_1");
};
export const Foo = /*#__PURE__*/ componentQrl(/*#__PURE__*/ qrl(i_HTDRsvUbLiE, "Foo_component_HTDRsvUbLiE"), {
tagName: "my-foo"
});


Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;;AAGA,OAAO,MAAM,cAAc,CAAC;IAC3B,qBACC,WAAC,iCACA;sBACC,WAAC;sBACD,UAAC;YAAQ,GAAG,KAAK;;;AAIrB,EAAE;AAEF,OAAO,MAAM,oBAAM,4EAuBhB;IACF,SAAS;AACV,GAAG\"}")
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;;;;AAGA,OAAO,MAAM,cAAc,CAAC;IAC3B,qBACC,WAAC,iCACA;sBACC,WAAC;sBACD,UAAC;4BAAW;0BAAA;;AAIhB,EAAE;AAEF,OAAO,MAAM,oBAAM,4EAuBhB;IACF,SAAS;AACV,GAAG\"}")
============================= test.tsx_Foo_component_HTDRsvUbLiE.js (ENTRY POINT)==

import { qrl } from "@qwik.dev/core";
Expand Down Expand Up @@ -109,6 +111,8 @@ Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"ma
import { useLexicalScope } from "@qwik.dev/core";
import { Lightweight } from "./test";
import { Fragment as _Fragment } from "@qwik.dev/core/jsx-runtime";
import { _getConstProps } from "@qwik.dev/core";
import { _getVarProps } from "@qwik.dev/core";
import { _jsxSorted } from "@qwik.dev/core";
import { _jsxSplit } from "@qwik.dev/core";
export const Foo_component_1_DvU6FitWglY = ()=>{
Expand All @@ -128,8 +132,8 @@ export const Foo_component_1_DvU6FitWglY = ()=>{
/*#__PURE__*/ _jsxSorted("div", null, {
class: "class"
}, /*#__PURE__*/ _jsxSplit(Lightweight, {
...props
}, null, null, 0, "u6_3"), 1, null),
..._getVarProps(props)
}, _getConstProps(props), null, 0, "u6_3"), 1, null),
/*#__PURE__*/ _jsxSorted("div", null, {
class: "class"
}, [
Expand All @@ -144,7 +148,7 @@ export const Foo_component_1_DvU6FitWglY = ()=>{
};


Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;2CAeU;;IACR,qBACC,WAAC;sBACA;0BACC,WAAC;gBAAI,OAAM;;0BACX,WAAC;gBAAI,OAAM;;0BACX,WAAC;gBAAI,OAAM;eAAQ;;sBAEpB,WAAC;YAAI,OAAM;yBACV,UAAC;YAAa,GAAG,KAAK;;sBAEvB,WAAC;YAAI,OAAM;;0BACV,WAAC;0BACD,WAAC;0BACD,WAAC;;sBAEF,WAAC;YAAI,OAAM;WACT\"}")
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;;;2CAeU;;IACR,qBACC,WAAC;sBACA;0BACC,WAAC;gBAAI,OAAM;;0BACX,WAAC;gBAAI,OAAM;;0BACX,WAAC;gBAAI,OAAM;eAAQ;;sBAEpB,WAAC;YAAI,OAAM;yBACV,UAAC;4BAAgB;0BAAA;sBAElB,WAAC;YAAI,OAAM;;0BACV,WAAC;0BACD,WAAC;0BACD,WAAC;;sBAEF,WAAC;YAAI,OAAM;WACT\"}")
/*
{
"origin": "test.tsx",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ import { useLexicalScope } from "@qwik.dev/core";
import { inlinedQrl } from "@qwik.dev/core";
import { _fnSignal } from "@qwik.dev/core";
import { _wrapProp } from "@qwik.dev/core";
import { _getVarProps } from "@qwik.dev/core";
import { _getConstProps } from "@qwik.dev/core";
import { _jsxSplit } from "@qwik.dev/core";
import { _jsxSorted } from "@qwik.dev/core";
export const Works = /*#__PURE__*/ componentQrl(/*#__PURE__*/ inlinedQrl((props)=>{
Expand Down Expand Up @@ -86,8 +88,9 @@ export const Works = /*#__PURE__*/ componentQrl(/*#__PURE__*/ inlinedQrl((props)
props
], "{some:p0.some??1+2}"),
class: _wrapProp(props, "count"),
...rest
..._getVarProps(rest)
}, {
..._getConstProps(rest),
override: true
}, _wrapProp(props, "count"), 0, "u6_0");
}, "Works_component_t45qL4vNGv0"));
Expand Down Expand Up @@ -119,7 +122,7 @@ export const NoWorks3 = /*#__PURE__*/ componentQrl(/*#__PURE__*/ inlinedQrl(({ c
}, "NoWorks3_component_fc13h5yYn14"));


Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;;;;;AAGA,OAAO,MAAM,sBAAQ,sCAAW;;;;;;;;IAO/B,QAAQ,GAAG,OAHX,aAFA,QAAO;IAMP,oCAAS,CAAC,EAAC,KAAK,EAAC;;QAChB,MAAM,UARP;QASC,QAAQ,GAAG,OATZ,OASoB,YANpB,aAFA,QAAO,SAGP,gBAAqB;;;;;IAOrB,qBACC,UAAC;QAAI,IAAI,qBAXV,QAAO;;;QAWW,MAAM,kBAAE,CAAA;gBAAE,IAAI,KAXhC,QAAO;YAW0B,CAAA;;;QAAG,KAAK;QAAU,GAAG,IAAI;;QAAE,QAAQ;;AAErE,mCAAG;AAEH,OAAO,MAAM,yBAAW,sCAAW,CAAC,EAAC,KAAK,EAAE,OAAO,EAAC,GAAG,EAAC,EAAC;IACxD,QAAQ,GAAG,CAAC;IACZ,oCAAS,CAAC,EAAC,KAAK,EAAC;;QAChB,MAAM,IAAM;QACZ,QAAQ,GAAG,CAAC;;;;IAEb,qBACC,WAAC;QAAI,OAAO;aAAQ;AAEtB,sCAAG;AAEH,OAAO,MAAM,yBAAW,sCAAW,CAAC,EAAC,KAAK,EAAE,QAAQ,MAAM,EAAC;IAC1D,QAAQ,GAAG,CAAC;IACZ,oCAAS,CAAC,EAAC,KAAK,EAAC;;QAChB,MAAM,IAAM;QACZ,QAAQ,GAAG,CAAC;;;;IAEb,qBACC,WAAC;QAAI,OAAO;aAAQ;AAEtB,sCAAG\"}")
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;;;;;;;AAGA,OAAO,MAAM,sBAAQ,sCAAW;;;;;;;;IAO/B,QAAQ,GAAG,OAHX,aAFA,QAAO;IAMP,oCAAS,CAAC,EAAC,KAAK,EAAC;;QAChB,MAAM,UARP;QASC,QAAQ,GAAG,OATZ,OASoB,YANpB,aAFA,QAAO,SAGP,gBAAqB;;;;;IAOrB,qBACC,UAAC;QAAI,IAAI,qBAXV,QAAO;;;QAWW,MAAM,kBAAE,CAAA;gBAAE,IAAI,KAXhC,QAAO;YAW0B,CAAA;;;QAAG,KAAK;wBAAa;;0BAAA;QAAM,QAAQ;;AAErE,mCAAG;AAEH,OAAO,MAAM,yBAAW,sCAAW,CAAC,EAAC,KAAK,EAAE,OAAO,EAAC,GAAG,EAAC,EAAC;IACxD,QAAQ,GAAG,CAAC;IACZ,oCAAS,CAAC,EAAC,KAAK,EAAC;;QAChB,MAAM,IAAM;QACZ,QAAQ,GAAG,CAAC;;;;IAEb,qBACC,WAAC;QAAI,OAAO;aAAQ;AAEtB,sCAAG;AAEH,OAAO,MAAM,yBAAW,sCAAW,CAAC,EAAC,KAAK,EAAE,QAAQ,MAAM,EAAC;IAC1D,QAAQ,GAAG,CAAC;IACZ,oCAAS,CAAC,EAAC,KAAK,EAAC;;QAChB,MAAM,IAAM;QACZ,QAAQ,GAAG,CAAC;;;;IAEb,qBACC,WAAC;QAAI,OAAO;aAAQ;AAEtB,sCAAG\"}")
== DIAGNOSTICS ==

[]
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"ma

import { Fragment as _Fragment } from "@qwik.dev/core/jsx-runtime";
import { createElement as _createElement } from "@qwik.dev/core";
import { _getConstProps } from "@qwik.dev/core";
import { _getVarProps } from "@qwik.dev/core";
import { _jsxSorted } from "@qwik.dev/core";
import { _jsxSplit } from "@qwik.dev/core";
import { _wrapProp } from "@qwik.dev/core";
Expand All @@ -78,8 +80,8 @@ export const RouterHead_component_DPA76mgIou0 = ()=>{
href: "/favicon.svg"
}, null, 3, null),
head.meta.map((m)=>/*#__PURE__*/ _jsxSplit("meta", {
...m
}, null, null, 0, "u6_0")),
..._getVarProps(m)
}, _getConstProps(m), null, 0, "u6_0")),
head.links.map((l)=>/*#__PURE__*/ _createElement("link", {
...l,
key: l.key
Expand All @@ -93,7 +95,7 @@ export const RouterHead_component_DPA76mgIou0 = ()=>{
};


Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;;;gDAOqC;IACpC,MAAM,OAAO;IACb,MAAM,MAAM;IAEZ,qBACA;sBACC,WAAC,qBAAO,KAAK,KAAK;sBAElB,WAAC;YAAK,KAAI;YAAY,IAAI,YAAE;;sBAC5B,WAAC;YAAK,MAAK;YAAW,SAAQ;;sBAC9B,WAAC;YAAK,KAAI;YAAO,MAAK;YAAgB,MAAK;;QAE1C,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,kBACf,UAAC;gBAAM,GAAG,CAAC;;QAGX,KAAK,KAAK,CAAC,GAAG,CAAC,CAAC,kBAChB,eAAC;gBAAM,GAAG,CAAC;gBAAE,KAAK,EAAE,GAAG;;QAGvB,KAAK,MAAM,CAAC,GAAG,CAAC,CAAC,kBACjB,eAAC;gBAAO,GAAG,EAAE,KAAK;gBAAE,yBAAyB,EAAE,KAAK;gBAAE,KAAK,EAAE,GAAG;;;AAInE\"}")
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;;;;;gDAOqC;IACpC,MAAM,OAAO;IACb,MAAM,MAAM;IAEZ,qBACA;sBACC,WAAC,qBAAO,KAAK,KAAK;sBAElB,WAAC;YAAK,KAAI;YAAY,IAAI,YAAE;;sBAC5B,WAAC;YAAK,MAAK;YAAW,SAAQ;;sBAC9B,WAAC;YAAK,KAAI;YAAO,MAAK;YAAgB,MAAK;;QAE1C,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,kBACf,UAAC;gCAAS;8BAAA;QAGV,KAAK,KAAK,CAAC,GAAG,CAAC,CAAC,kBAChB,eAAC;gBAAM,GAAG,CAAC;gBAAE,KAAK,EAAE,GAAG;;QAGvB,KAAK,MAAM,CAAC,GAAG,CAAC,CAAC,kBACjB,eAAC;gBAAO,GAAG,EAAE,KAAK;gBAAE,yBAAyB,EAAE,KAAK;gBAAE,KAAK,EAAE,GAAG;;;AAInE\"}")
/*
{
"origin": "test.tsx",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export default /*#__PURE__*/ componentQrl(/*#__PURE__*/ qrl(i_LUXeXe0DQrg, "test
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;AAGE,uDAAuD;AACvD,0CAA0C;AAC1C,6BAAe,6EAab\"}")
============================= test.tsx_test_component_LUXeXe0DQrg.js (ENTRY POINT)==

import { _getConstProps } from "@qwik.dev/core";
import { _getVarProps } from "@qwik.dev/core";
import { _jsxSorted } from "@qwik.dev/core";
import { _jsxSplit } from "@qwik.dev/core";
import { _restProps } from "@qwik.dev/core";
Expand All @@ -60,8 +62,8 @@ export const test_component_LUXeXe0DQrg = (props)=>{
id: _wrapProp(props, "id")
}, null, [
/*#__PURE__*/ _jsxSplit("span", {
...rest
}, null, [
..._getVarProps(rest)
}, _getConstProps(rest), [
_wrapProp(props, "message"),
" ",
_wrapProp(props, "count")
Expand All @@ -73,7 +75,7 @@ export const test_component_LUXeXe0DQrg = (props)=>{
};


Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;0CAK4B;;;;;;IACzB,MAAM,UAAU,SAAS;QAAE,SAAS;IAAE,GAAG;QAAE,UAAU;IAAM;IAC3D,QAAQ,OAAO;IACf,MAAM,YAAY,QAAQ,OAAO,GAAG;IACpC,qBACC,WAAC;QAAI,EAAE;;sBACN,UAAC;YAAM,GAAG,IAAI;;;YACL;;;sBAET,WAAC;YAAI,OAAM;WAAW;;AAGzB\"}")
Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;;0CAK4B;;;;;;IACzB,MAAM,UAAU,SAAS;QAAE,SAAS;IAAE,GAAG;QAAE,UAAU;IAAM;IAC3D,QAAQ,OAAO;IACf,MAAM,YAAY,QAAQ,OAAO,GAAG;IACpC,qBACC,WAAC;QAAI,EAAE;;sBACN,UAAC;4BAAS;0BAAA;;YACD;;;sBAET,WAAC;YAAI,OAAM;WAAW;;AAGzB\"}")
/*
{
"origin": "test.tsx",
Expand Down
Loading
Loading