From dfead2836eb5444335fae1d502b6e4150bbe464f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Thu, 18 Nov 2021 16:57:33 +0100 Subject: [PATCH] big change: shallow render With this commit, component only render child components if they have different props (shallow equality). Otherwise, we trust the reactivity system to make sure that all impacted components are updated --- src/compiler/code_generator.ts | 4 +- src/component/component.ts | 2 + src/component/component_node.ts | 21 +++- .../__snapshots__/basics.test.ts.snap | 2 +- .../__snapshots__/concurrency.test.ts.snap | 2 +- .../__snapshots__/error_handling.test.ts.snap | 18 +-- .../__snapshots__/lifecycle.test.ts.snap | 2 +- .../__snapshots__/refs.test.ts.snap | 2 +- .../__snapshots__/rendering.test.ts.snap | 27 +++++ .../__snapshots__/slots.test.ts.snap | 108 +++++++++--------- .../__snapshots__/t_props.test.ts.snap | 4 +- .../__snapshots__/t_set.test.ts.snap | 2 +- tests/components/concurrency.test.ts | 7 +- tests/components/lifecycle.test.ts | 11 +- tests/components/rendering.test.ts | 49 ++++++++ tests/components/t_props.test.ts | 2 +- tests/misc/__snapshots__/memo.test.ts.snap | 6 +- tests/misc/__snapshots__/portal.test.ts.snap | 40 +++---- tests/reactivity.test.ts | 2 +- 19 files changed, 198 insertions(+), 113 deletions(-) create mode 100644 tests/components/__snapshots__/rendering.test.ts.snap create mode 100644 tests/components/rendering.test.ts diff --git a/src/compiler/code_generator.ts b/src/compiler/code_generator.ts index 11251e0b..9fb24181 100644 --- a/src/compiler/code_generator.ts +++ b/src/compiler/code_generator.ts @@ -948,7 +948,7 @@ export class CodeGenerator { let propString = propStr; if (ast.dynamicProps) { if (!props.length) { - propString = `${compileExpr(ast.dynamicProps)}`; + propString = `Object.assign({}, ${compileExpr(ast.dynamicProps)})`; } else { propString = `Object.assign({}, ${compileExpr(ast.dynamicProps)}, ${propStr})`; } @@ -1012,7 +1012,7 @@ export class CodeGenerator { keyArg = `${ctx.tKeyExpr} + ${keyArg}`; } const blockArgs = `${expr}, ${propString}, ${keyArg}, node, ctx`; - let blockExpr = `component(${blockArgs})`; + let blockExpr = `component(${blockArgs}${hasSlot ? ", true" : ""})`; if (Object.keys(extraArgs).length) { this.shouldDefineAssign = true; const content = Object.keys(extraArgs).map((k) => `${k}: ${extraArgs[k]}`); diff --git a/src/component/component.ts b/src/component/component.ts index b3c48f3a..cec032a6 100644 --- a/src/component/component.ts +++ b/src/component/component.ts @@ -1,6 +1,8 @@ import type { Env } from "../app/app"; import type { ComponentNode } from "./component_node"; +export type Props = { [key: string]: any }; + // ----------------------------------------------------------------------------- // Component Class // ----------------------------------------------------------------------------- diff --git a/src/component/component_node.ts b/src/component/component_node.ts index 897b4c4d..c65809aa 100644 --- a/src/component/component_node.ts +++ b/src/component/component_node.ts @@ -1,6 +1,6 @@ import type { App, Env } from "../app/app"; import { BDom, VNode } from "../blockdom"; -import { Component } from "./component"; +import { Component, Props } from "./component"; import { Fiber, makeChildFiber, @@ -15,12 +15,21 @@ import { applyDefaultProps } from "./props_validation"; import { STATUS } from "./status"; import { applyStyles } from "./style"; +function arePropsDifferent(props1: Props, props2: Props): boolean { + for (let k in props1) { + if (props1[k] !== props2[k]) { + return true; + } + } + return false; +} export function component( name: string | typeof Component, props: any, key: string, ctx: ComponentNode, - parent: any + parent: any, + hasSlots: boolean = false ): ComponentNode { let node: any = ctx.children[key]; let isDynamic = typeof name !== "string"; @@ -39,7 +48,9 @@ export function component( const parentFiber = ctx.fiber!; if (node) { - node.updateAndRender(props, parentFiber); + if (hasSlots || arePropsDifferent(node.component.props, props)) { + node.updateAndRender(props, parentFiber); + } } else { // new component let C; @@ -241,6 +252,10 @@ export class ComponentNode } patch() { + if (!this.fiber) { + // component was not rendered => no need to do anything + return; + } this.bdom!.patch(this!.fiber!.bdom!, false); this.fiber!.appliedToDom = true; this.fiber = null; diff --git a/tests/components/__snapshots__/basics.test.ts.snap b/tests/components/__snapshots__/basics.test.ts.snap index 41d5ff4b..12e71c65 100644 --- a/tests/components/__snapshots__/basics.test.ts.snap +++ b/tests/components/__snapshots__/basics.test.ts.snap @@ -1020,7 +1020,7 @@ exports[`basics update props of component without concrete own node 3`] = ` return function template(ctx, node, key = \\"\\") { const tKey_1 = ctx['childProps'].key; - let b2 = toggler(tKey_1, component(\`Child\`, ctx['childProps'], tKey_1 + key + \`__2\`, node, ctx)); + let b2 = toggler(tKey_1, component(\`Child\`, Object.assign({}, ctx['childProps']), tKey_1 + key + \`__2\`, node, ctx)); return block1([], [b2]); } }" diff --git a/tests/components/__snapshots__/concurrency.test.ts.snap b/tests/components/__snapshots__/concurrency.test.ts.snap index 53704e5e..aa22e42d 100644 --- a/tests/components/__snapshots__/concurrency.test.ts.snap +++ b/tests/components/__snapshots__/concurrency.test.ts.snap @@ -1067,7 +1067,7 @@ exports[`properly behave when destroyed/unmounted while rendering 2`] = ` let block1 = createBlock(\`
\`); return function template(ctx, node, key = \\"\\") { - let b2 = component(\`SubChild\`, {}, key + \`__1\`, node, ctx); + let b2 = component(\`SubChild\`, {val: ctx['props'].val}, key + \`__1\`, node, ctx); return block1([], [b2]); } }" diff --git a/tests/components/__snapshots__/error_handling.test.ts.snap b/tests/components/__snapshots__/error_handling.test.ts.snap index 30916e66..870cd689 100644 --- a/tests/components/__snapshots__/error_handling.test.ts.snap +++ b/tests/components/__snapshots__/error_handling.test.ts.snap @@ -126,7 +126,7 @@ exports[`can catch errors can catch an error in a component render function 3`] } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -230,7 +230,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon } return function template(ctx, node, key = \\"\\") { - let b5 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b5 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b5]); } }" @@ -250,7 +250,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -305,7 +305,7 @@ exports[`can catch errors can catch an error in the initial call of a component } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -362,7 +362,7 @@ exports[`can catch errors can catch an error in the initial call of a component return function template(ctx, node, key = \\"\\") { let b3; if (ctx['state'].flag) { - b3 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + b3 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } return block1([], [b3]); } @@ -417,7 +417,7 @@ exports[`can catch errors can catch an error in the mounted call 3`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -473,7 +473,7 @@ exports[`can catch errors can catch an error in the willPatch call 3`] = ` return function template(ctx, node, key = \\"\\") { let d1 = ctx['state'].message; - let b3 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([d1], [b3]); } }" @@ -527,7 +527,7 @@ exports[`can catch errors can catch an error in the willStart call 3`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -597,7 +597,7 @@ exports[`can catch errors can catch an error origination from a child's willStar } return function template(ctx, node, key = \\"\\") { - let b5 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b5 = assign(component(\`ErrorBoundary\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b5]); } }" diff --git a/tests/components/__snapshots__/lifecycle.test.ts.snap b/tests/components/__snapshots__/lifecycle.test.ts.snap index b6a6c446..bffaee04 100644 --- a/tests/components/__snapshots__/lifecycle.test.ts.snap +++ b/tests/components/__snapshots__/lifecycle.test.ts.snap @@ -555,7 +555,7 @@ exports[`lifecycle hooks onWillRender 2`] = ` let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; return function template(ctx, node, key = \\"\\") { - return component(\`Child\`, {}, key + \`__1\`, node, ctx); + return component(\`Child\`, {someValue: ctx['state'].value}, key + \`__1\`, node, ctx); } }" `; diff --git a/tests/components/__snapshots__/refs.test.ts.snap b/tests/components/__snapshots__/refs.test.ts.snap index 661bde6d..88c9c823 100644 --- a/tests/components/__snapshots__/refs.test.ts.snap +++ b/tests/components/__snapshots__/refs.test.ts.snap @@ -53,7 +53,7 @@ exports[`refs refs are properly bound in slots 2`] = ` const refs = ctx.__owl__.refs; let d1 = ctx['state'].val; const ctx2 = capture(ctx); - let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'footer': slot3(ctx2)}}); + let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'footer': slot3(ctx2)}}); return block1([d1], [b3]); } }" diff --git a/tests/components/__snapshots__/rendering.test.ts.snap b/tests/components/__snapshots__/rendering.test.ts.snap new file mode 100644 index 00000000..24686781 --- /dev/null +++ b/tests/components/__snapshots__/rendering.test.ts.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`rendering semantics can render a parent without rendering child 1`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component } = bdom; + let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; + + return function template(ctx, node, key = \\"\\") { + return text(\`child\`); + } +}" +`; + +exports[`rendering semantics can render a parent without rendering child 2`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component } = bdom; + let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; + + return function template(ctx, node, key = \\"\\") { + let b2 = text(ctx['state'].value); + let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx); + return multi([b2, b3]); + } +}" +`; diff --git a/tests/components/__snapshots__/slots.test.ts.snap b/tests/components/__snapshots__/slots.test.ts.snap index 67d22566..ee54cbb9 100644 --- a/tests/components/__snapshots__/slots.test.ts.snap +++ b/tests/components/__snapshots__/slots.test.ts.snap @@ -37,7 +37,7 @@ exports[`slots can define and call slots 2`] = ` return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - let b4 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'header': slot3(ctx2), 'footer': slot4(ctx2)}}); + let b4 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'header': slot3(ctx2), 'footer': slot4(ctx2)}}); return block1([], [b4]); } }" @@ -74,7 +74,7 @@ exports[`slots can render node with t-ref and Component in same slot 2`] = ` return function template(ctx, node, key = \\"\\") { const refs = ctx.__owl__.refs; - return assign(component(\`Child\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + return assign(component(\`Child\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } }" `; @@ -117,7 +117,7 @@ exports[`slots content is the default slot (variation) 2`] = ` } return function template(ctx, node, key = \\"\\") { - return assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + return assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } }" `; @@ -152,7 +152,7 @@ exports[`slots content is the default slot 2`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -226,7 +226,7 @@ exports[`slots default content is not rendered if named slot is provided 2`] = ` return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'header': slot3(ctx2)}}); + let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'header': slot3(ctx2)}}); return block1([], [b3]); } }" @@ -265,7 +265,7 @@ exports[`slots default content is not rendered if slot is provided 2`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -310,7 +310,7 @@ exports[`slots default slot next to named slot, with default content 2`] = ` return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'footer': slot3(ctx2)}}); + let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'footer': slot3(ctx2)}}); return block1([], [b3]); } }" @@ -340,7 +340,7 @@ exports[`slots default slot work with text nodes (variation) 2`] = ` } return function template(ctx, node, key = \\"\\") { - return assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + return assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } }" `; @@ -374,7 +374,7 @@ exports[`slots default slot work with text nodes 2`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -422,7 +422,7 @@ exports[`slots dynamic t-slot call 2`] = ` return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - let b6 = assign(component(\`Toggler\`, {}, key + \`__1\`, node, ctx), {slots: {'slot1': slot3(ctx2), 'slot2': slot4(ctx2)}}); + let b6 = assign(component(\`Toggler\`, {}, key + \`__1\`, node, ctx, true), {slots: {'slot1': slot3(ctx2), 'slot2': slot4(ctx2)}}); return block1([], [b6]); } }" @@ -473,7 +473,7 @@ exports[`slots dynamic t-slot call with default 2`] = ` return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - let b6 = assign(component(\`Toggler\`, {}, key + \`__1\`, node, ctx), {slots: {'slot1': slot3(ctx2), 'slot2': slot4(ctx2)}}); + let b6 = assign(component(\`Toggler\`, {}, key + \`__1\`, node, ctx, true), {slots: {'slot1': slot3(ctx2), 'slot2': slot4(ctx2)}}); return block1([], [b6]); } }" @@ -505,7 +505,7 @@ exports[`slots fun: two calls to the same slot 2`] = ` } return function template(ctx, node, key = \\"\\") { - return assign(component(\`Child\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + return assign(component(\`Child\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } }" `; @@ -574,7 +574,7 @@ exports[`slots multiple roots are allowed in a default slot 2`] = ` } return function template(ctx, node, key = \\"\\") { - let b5 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b5 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b5]); } }" @@ -614,7 +614,7 @@ exports[`slots multiple roots are allowed in a named slot 2`] = ` return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - let b5 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'content': slot3(ctx2)}}); + let b5 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'content': slot3(ctx2)}}); return block1([], [b5]); } }" @@ -668,7 +668,7 @@ exports[`slots multiple slots containing components 3`] = ` return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - return assign(component(\`B\`, {}, key + \`__1\`, node, ctx), {slots: {'s1': slot3(ctx2), 's2': slot5(ctx2)}}); + return assign(component(\`B\`, {}, key + \`__1\`, node, ctx, true), {slots: {'s1': slot3(ctx2), 's2': slot5(ctx2)}}); } }" `; @@ -707,7 +707,7 @@ exports[`slots named slot inside slot 2`] = ` const slot4 = ctx => (node, key) => { const ctx6 = capture(ctx); - return assign(component(\`Child\`, {}, key + \`__5\`, node, ctx), {slots: {'brol': slot7(ctx6)}}); + return assign(component(\`Child\`, {}, key + \`__5\`, node, ctx, true), {slots: {'brol': slot7(ctx6)}}); } const slot7 = ctx => (node, key) => { @@ -717,7 +717,7 @@ exports[`slots named slot inside slot 2`] = ` return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - let b5 = assign(component(\`Child\`, {}, key + \`__1\`, node, ctx), {slots: {'brol': slot3(ctx2), 'default': slot4(ctx2)}}); + let b5 = assign(component(\`Child\`, {}, key + \`__1\`, node, ctx, true), {slots: {'brol': slot3(ctx2), 'default': slot4(ctx2)}}); return block1([], [b5]); } }" @@ -757,7 +757,7 @@ exports[`slots named slot inside slot, part 3 2`] = ` const slot4 = ctx => (node, key) => { const ctx6 = capture(ctx); - return assign(component(\`Child\`, {}, key + \`__5\`, node, ctx), {slots: {'brol': slot7(ctx6)}}); + return assign(component(\`Child\`, {}, key + \`__5\`, node, ctx, true), {slots: {'brol': slot7(ctx6)}}); } const slot7 = ctx => (node, key) => { @@ -767,7 +767,7 @@ exports[`slots named slot inside slot, part 3 2`] = ` return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - let b5 = assign(component(\`Child\`, {}, key + \`__1\`, node, ctx), {slots: {'brol': slot3(ctx2), 'default': slot4(ctx2)}}); + let b5 = assign(component(\`Child\`, {}, key + \`__1\`, node, ctx, true), {slots: {'brol': slot3(ctx2), 'default': slot4(ctx2)}}); return block1([], [b5]); } }" @@ -850,7 +850,7 @@ exports[`slots named slots inside slot, again 2`] = ` const slot4 = ctx => (node, key) => { const ctx6 = capture(ctx); - return assign(component(\`Child\`, {}, key + \`__5\`, node, ctx), {slots: {'brol2': slot7(ctx6)}}); + return assign(component(\`Child\`, {}, key + \`__5\`, node, ctx, true), {slots: {'brol2': slot7(ctx6)}}); } const slot7 = ctx => (node, key) => { @@ -860,7 +860,7 @@ exports[`slots named slots inside slot, again 2`] = ` return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - let b5 = assign(component(\`Child\`, {}, key + \`__1\`, node, ctx), {slots: {'brol1': slot3(ctx2), 'default': slot4(ctx2)}}); + let b5 = assign(component(\`Child\`, {}, key + \`__1\`, node, ctx, true), {slots: {'brol1': slot3(ctx2), 'default': slot4(ctx2)}}); return block1([], [b5]); } }" @@ -920,7 +920,7 @@ exports[`slots nested slots in same template 4`] = ` let block1 = createBlock(\`\`); const slot2 = ctx => (node, key) => { - return assign(component(\`Child2\`, {}, key + \`__3\`, node, ctx), {slots: {'default': slot4(ctx)}}); + return assign(component(\`Child2\`, {}, key + \`__3\`, node, ctx, true), {slots: {'default': slot4(ctx)}}); } const slot4 = ctx => (node, key) => { @@ -928,7 +928,7 @@ exports[`slots nested slots in same template 4`] = ` } return function template(ctx, node, key = \\"\\") { - let b4 = assign(component(\`Child\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b4 = assign(component(\`Child\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b4]); } }" @@ -976,7 +976,7 @@ exports[`slots nested slots: evaluation context and parented relationship 3`] = } return function template(ctx, node, key = \\"\\") { - return assign(component(\`GrandChild\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + return assign(component(\`GrandChild\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } }" `; @@ -993,7 +993,7 @@ exports[`slots nested slots: evaluation context and parented relationship 4`] = } return function template(ctx, node, key = \\"\\") { - return assign(component(\`Child\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + return assign(component(\`Child\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } }" `; @@ -1052,7 +1052,7 @@ exports[`slots simple default slot 2`] = ` } return function template(ctx, node, key = \\"\\") { - return assign(component(\`Child\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + return assign(component(\`Child\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } }" `; @@ -1081,7 +1081,7 @@ exports[`slots simple default slot, variation 2`] = ` } return function template(ctx, node, key = \\"\\") { - return assign(component(\`Child\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + return assign(component(\`Child\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } }" `; @@ -1131,7 +1131,7 @@ exports[`slots slot and (inline) t-call 3`] = ` return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot3(ctx2)}}); + let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot3(ctx2)}}); return block1([], [b3]); } }" @@ -1182,7 +1182,7 @@ exports[`slots slot and t-call 3`] = ` return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot3(ctx2)}}); + let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot3(ctx2)}}); return block1([], [b3]); } }" @@ -1217,7 +1217,7 @@ exports[`slots slot and t-esc 2`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -1270,7 +1270,7 @@ exports[`slots slot are properly rendered if inner props are changed 3`] = ` const v1 = ctx['inc']; let d1 = [v1, ctx]; let d2 = ctx['state'].val; - let b3 = assign(component(\`GenericComponent\`, {}, key + \`__2\`, node, ctx), {slots: {'default': slot3(ctx)}}); + let b3 = assign(component(\`GenericComponent\`, {}, key + \`__2\`, node, ctx, true), {slots: {'default': slot3(ctx)}}); return block1([d1, d2], [b3]); } }" @@ -1307,7 +1307,7 @@ exports[`slots slot content is bound to caller 2`] = ` } return function template(ctx, node, key = \\"\\") { - return assign(component(\`Child\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + return assign(component(\`Child\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } }" `; @@ -1350,7 +1350,7 @@ exports[`slots slot preserves properly parented relationship 3`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Child\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Child\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -1408,7 +1408,7 @@ exports[`slots slot preserves properly parented relationship, even through t-cal return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - let b3 = assign(component(\`Child\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot3(ctx2)}}); + let b3 = assign(component(\`Child\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot3(ctx2)}}); return block1([], [b3]); } }" @@ -1441,7 +1441,7 @@ exports[`slots slots and wrapper components 2`] = ` } return function template(ctx, node, key = \\"\\") { - return assign(component(\`Link\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + return assign(component(\`Link\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } }" `; @@ -1480,7 +1480,7 @@ exports[`slots slots are rendered with proper context 2`] = ` return function template(ctx, node, key = \\"\\") { let d1 = ctx['state'].val; const ctx2 = capture(ctx); - let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'footer': slot3(ctx2)}}); + let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'footer': slot3(ctx2)}}); return block1([d1], [b3]); } }" @@ -1525,7 +1525,7 @@ exports[`slots slots are rendered with proper context, part 2 2`] = ` ctx[\`user\`] = v_block2[i1]; let key1 = ctx['user'].id; const ctx2 = capture(ctx); - let b7 = assign(component(\`Link\`, {to: '/user/'+ctx['user'].id}, key + \`__1__\${key1}\`, node, ctx), {slots: {'default': slot3(ctx2)}}); + let b7 = assign(component(\`Link\`, {to: '/user/'+ctx['user'].id}, key + \`__1__\${key1}\`, node, ctx, true), {slots: {'default': slot3(ctx2)}}); c_block2[i1] = withKey(block3([], [b7]), key1); } let b2 = list(c_block2); @@ -1574,7 +1574,7 @@ exports[`slots slots are rendered with proper context, part 3 2`] = ` let key1 = ctx['user'].id; setContextValue(ctx, \\"userdescr\\", 'User '+ctx['user'].name); const ctx2 = capture(ctx); - let b5 = assign(component(\`Link\`, {to: '/user/'+ctx['user'].id}, key + \`__1__\${key1}\`, node, ctx), {slots: {'default': slot3(ctx2)}}); + let b5 = assign(component(\`Link\`, {to: '/user/'+ctx['user'].id}, key + \`__1__\${key1}\`, node, ctx, true), {slots: {'default': slot3(ctx2)}}); c_block2[i1] = withKey(block3([], [b5]), key1); } let b2 = list(c_block2); @@ -1617,7 +1617,7 @@ exports[`slots slots are rendered with proper context, part 4 2`] = ` ctx[isBoundary] = 1 setContextValue(ctx, \\"userdescr\\", 'User '+ctx['state'].user.name); const ctx2 = capture(ctx); - let b3 = assign(component(\`Link\`, {to: '/user/'+ctx['state'].user.id}, key + \`__1\`, node, ctx), {slots: {'default': slot3(ctx2)}}); + let b3 = assign(component(\`Link\`, {to: '/user/'+ctx['state'].user.id}, key + \`__1\`, node, ctx, true), {slots: {'default': slot3(ctx2)}}); return block1([], [b3]); } }" @@ -1652,7 +1652,7 @@ exports[`slots slots in slots, with vars 2`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`B\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`B\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -1678,7 +1678,7 @@ exports[`slots slots in slots, with vars 3`] = ` ctx[isBoundary] = 1 setContextValue(ctx, \\"test\\", ctx['state'].name); const ctx2 = capture(ctx); - let b3 = assign(component(\`A\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot3(ctx2)}}); + let b3 = assign(component(\`A\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot3(ctx2)}}); return block1([], [b3]); } }" @@ -1721,7 +1721,7 @@ exports[`slots slots in t-foreach and re-rendering 2`] = ` ctx[\`n_index\`] = i1; let key1 = ctx['n_index']; const ctx2 = capture(ctx); - c_block2[i1] = withKey(assign(component(\`Child\`, {}, key + \`__1__\${key1}\`, node, ctx), {slots: {'default': slot3(ctx2)}}), key1); + c_block2[i1] = withKey(assign(component(\`Child\`, {}, key + \`__1__\${key1}\`, node, ctx, true), {slots: {'default': slot3(ctx2)}}), key1); } let b2 = list(c_block2); return block1([], [b2]); @@ -1775,7 +1775,7 @@ exports[`slots slots in t-foreach in t-foreach 2`] = ` ctx[\`node2\`] = v_block6[i2]; let key2 = ctx['node2'].key; const ctx2 = capture(ctx); - c_block6[i2] = withKey(assign(component(\`Child\`, {}, key + \`__1__\${key1}__\${key2}\`, node, ctx), {slots: {'default': slot3(ctx2)}}), key2); + c_block6[i2] = withKey(assign(component(\`Child\`, {}, key + \`__1__\${key1}__\${key2}\`, node, ctx, true), {slots: {'default': slot3(ctx2)}}), key2); } ctx = ctx.__proto__; let b6 = list(c_block6); @@ -1828,7 +1828,7 @@ exports[`slots slots in t-foreach with t-set and re-rendering 2`] = ` let key1 = ctx['n_index']; setContextValue(ctx, \\"dummy\\", ctx['n_index']); const ctx2 = capture(ctx); - c_block2[i1] = withKey(assign(component(\`Child\`, {}, key + \`__1__\${key1}\`, node, ctx), {slots: {'default': slot3(ctx2)}}), key1); + c_block2[i1] = withKey(assign(component(\`Child\`, {}, key + \`__1__\${key1}\`, node, ctx, true), {slots: {'default': slot3(ctx2)}}), key1); } let b2 = list(c_block2); return block1([], [b2]); @@ -1867,7 +1867,7 @@ exports[`slots t-debug on a t-set-slot (defining a slot) 2`] = ` return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'content': slot3(ctx2)}}); + let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'content': slot3(ctx2)}}); return block1([], [b3]); } }" @@ -1906,7 +1906,7 @@ exports[`slots t-set t-value in a slot 2`] = ` ctx = Object.create(ctx); ctx[isBoundary] = 1 const ctx2 = capture(ctx); - let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot3(ctx2)}}); + let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot3(ctx2)}}); return block1([], [b3]); } }" @@ -1968,7 +1968,7 @@ exports[`slots t-slot in recursive templates 2`] = ` ctx = Object.create(ctx); ctx[isBoundary] = 1 const ctx2 = capture(ctx); - return assign(component(\`Wrapper\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot3(ctx2)}}); + return assign(component(\`Wrapper\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot3(ctx2)}}); } }" `; @@ -2027,7 +2027,7 @@ exports[`slots t-slot nested within another slot 4`] = ` let block1 = createBlock(\`\`); const slot2 = ctx => (node, key) => { - return assign(component(\`Portal\`, {}, key + \`__3\`, node, ctx), {slots: {'default': slot4(ctx)}}); + return assign(component(\`Portal\`, {}, key + \`__3\`, node, ctx, true), {slots: {'default': slot4(ctx)}}); } const slot4 = ctx => (node, key) => { @@ -2035,7 +2035,7 @@ exports[`slots t-slot nested within another slot 4`] = ` } return function template(ctx, node, key = \\"\\") { - let b4 = assign(component(\`Modal\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b4 = assign(component(\`Modal\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b4]); } }" @@ -2055,7 +2055,7 @@ exports[`slots t-slot nested within another slot 5`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -2090,7 +2090,7 @@ exports[`slots t-slot scope context 2`] = ` } return function template(ctx, node, key = \\"\\") { - return assign(component(\`Wrapper\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + return assign(component(\`Wrapper\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } }" `; @@ -2109,7 +2109,7 @@ exports[`slots t-slot scope context 3`] = ` } return function template(ctx, node, key = \\"\\") { - return assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + return assign(component(\`Dialog\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } }" `; @@ -2174,7 +2174,7 @@ exports[`slots t-slot within dynamic t-call 4`] = ` return function template(ctx, node, key = \\"\\") { const ctx2 = capture(ctx); - let b3 = assign(component(\`Slotted\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot3(ctx2)}}); + let b3 = assign(component(\`Slotted\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot3(ctx2)}}); return block1([], [b3]); } }" @@ -2221,7 +2221,7 @@ exports[`slots template can just return a slot 3`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`SlotComponent\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`SlotComponent\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" diff --git a/tests/components/__snapshots__/t_props.test.ts.snap b/tests/components/__snapshots__/t_props.test.ts.snap index 2c353109..d3116a06 100644 --- a/tests/components/__snapshots__/t_props.test.ts.snap +++ b/tests/components/__snapshots__/t_props.test.ts.snap @@ -24,7 +24,7 @@ exports[`t-props basic use 2`] = ` let block1 = createBlock(\`
\`); return function template(ctx, node, key = \\"\\") { - let b2 = component(\`Child\`, ctx['some'].obj, key + \`__1\`, node, ctx); + let b2 = component(\`Child\`, Object.assign({}, ctx['some'].obj), key + \`__1\`, node, ctx); return block1([], [b2]); } }" @@ -85,7 +85,7 @@ exports[`t-props t-props only 2`] = ` let block1 = createBlock(\`
\`); return function template(ctx, node, key = \\"\\") { - let b2 = component(\`Comp\`, ctx['state'], key + \`__1\`, node, ctx); + let b2 = component(\`Comp\`, Object.assign({}, ctx['state']), key + \`__1\`, node, ctx); return block1([], [b2]); } }" diff --git a/tests/components/__snapshots__/t_set.test.ts.snap b/tests/components/__snapshots__/t_set.test.ts.snap index 1c5d699a..60022fb8 100644 --- a/tests/components/__snapshots__/t_set.test.ts.snap +++ b/tests/components/__snapshots__/t_set.test.ts.snap @@ -38,7 +38,7 @@ exports[`t-set slot setted value (with t-set) not accessible with t-esc 2`] = ` setContextValue(ctx, \\"iter\\", 'source'); let d1 = ctx['iter']; const ctx2 = capture(ctx); - let b2 = assign(component(\`Childcomp\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot3(ctx2)}}); + let b2 = assign(component(\`Childcomp\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot3(ctx2)}}); let d2 = ctx['iter']; return block1([d1, d2], [b2]); } diff --git a/tests/components/concurrency.test.ts b/tests/components/concurrency.test.ts index 3f8a2743..6bfe85fb 100644 --- a/tests/components/concurrency.test.ts +++ b/tests/components/concurrency.test.ts @@ -543,7 +543,7 @@ test("properly behave when destroyed/unmounted while rendering ", async () => { } class Child extends Component { - static template = xml`
`; + static template = xml`
`; static components = { SubChild }; setup() { useLogLifecycle(steps); @@ -1900,18 +1900,13 @@ test("concurrent renderings scenario 13", async () => { "Child:willPatch", "Child:patched", "Parent:willRender", - "Child:willUpdateProps", "Child:setup", "Child:willStart", "Parent:rendered", "Child:willRender", "Child:rendered", - "Child:willRender", - "Child:rendered", "Parent:willPatch", - "Child:willPatch", "Child:mounted", - "Child:patched", "Parent:patched", "Child:willRender", "Child:rendered", diff --git a/tests/components/lifecycle.test.ts b/tests/components/lifecycle.test.ts index 4b877991..8f79ec87 100644 --- a/tests/components/lifecycle.test.ts +++ b/tests/components/lifecycle.test.ts @@ -899,8 +899,9 @@ describe("lifecycle hooks", () => { class Parent extends Component { static template = xml` - `; + `; static components = { Child }; + state = useState({ value: 1 }); setup() { useLogLifecycle(steps); } @@ -910,7 +911,7 @@ describe("lifecycle hooks", () => { expect(fixture.innerHTML).toBe(""); - parent.render(); // to block child render + parent.state.value++; // to block child render await nextTick(); fixture.querySelector("button")!.click(); @@ -1063,22 +1064,18 @@ describe("lifecycle hooks", () => { steps.splice(0); c!.state.flag = false; await nextTick(); + expect(fixture.innerHTML).toBe(`
A
B
C
D
F
`); expect(steps).toEqual([ "C:willRender", - "D:willUpdateProps", "F:setup", "F:willStart", "C:rendered", - "D:willRender", - "D:rendered", "F:willRender", "F:rendered", "C:willPatch", - "D:willPatch", "E:willUnmount", "E:destroyed", "F:mounted", - "D:patched", "C:patched", ]); }); diff --git a/tests/components/rendering.test.ts b/tests/components/rendering.test.ts new file mode 100644 index 00000000..8350822e --- /dev/null +++ b/tests/components/rendering.test.ts @@ -0,0 +1,49 @@ +import { Component, mount, onRendered, useState } from "../../src"; +import { xml } from "../../src/tags"; +import { makeTestFixture, snapshotEverything, nextTick } from "../helpers"; + +let fixture: HTMLElement; + +snapshotEverything(); + +beforeEach(() => { + fixture = makeTestFixture(); +}); + +describe("rendering semantics", () => { + test("can render a parent without rendering child", async () => { + let childN = 0; + let parentN = 0; + class Child extends Component { + static template = xml`child`; + setup() { + onRendered(() => childN++); + } + } + + class Parent extends Component { + static template = xml` + + + `; + static components = { Child }; + + state = useState({ value: "A" }); + setup() { + onRendered(() => parentN++); + } + } + + const parent = await mount(Parent, fixture); + + expect(fixture.innerHTML).toBe("Achild"); + expect(parentN).toBe(1); + expect(childN).toBe(1); + + parent.state.value = "B"; + await nextTick(); + expect(fixture.innerHTML).toBe("Bchild"); + expect(parentN).toBe(2); + expect(childN).toBe(1); + }); +}); diff --git a/tests/components/t_props.test.ts b/tests/components/t_props.test.ts index ce78d09b..6d7bfc2a 100644 --- a/tests/components/t_props.test.ts +++ b/tests/components/t_props.test.ts @@ -65,7 +65,7 @@ describe("t-props", () => { `; setup() { expect(this.props).toEqual({ a: 1, b: 2 }); - expect(this.props).toBe(props); + expect(this.props).not.toBe(props); } } class Parent extends Component { diff --git a/tests/misc/__snapshots__/memo.test.ts.snap b/tests/misc/__snapshots__/memo.test.ts.snap index 1422ec5d..4e3487cf 100644 --- a/tests/misc/__snapshots__/memo.test.ts.snap +++ b/tests/misc/__snapshots__/memo.test.ts.snap @@ -30,7 +30,7 @@ exports[`Memo if no prop change, prevent renderings from above 2`] = ` let b2 = text(ctx['state'].a); let b3 = text(ctx['state'].b); let b4 = text(ctx['state'].c); - let b9 = assign(component(\`Memo\`, {a: ctx['state'].a,b: ctx['state'].b}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b9 = assign(component(\`Memo\`, {a: ctx['state'].a,b: ctx['state'].b}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return multi([b2, b3, b4, b9]); } }" @@ -61,7 +61,7 @@ exports[`Memo if no props, prevent renderings from above 2`] = ` return function template(ctx, node, key = \\"\\") { let b2 = component(\`Child\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx); - let b4 = assign(component(\`Memo\`, {}, key + \`__2\`, node, ctx), {slots: {'default': slot3(ctx)}}); + let b4 = assign(component(\`Memo\`, {}, key + \`__2\`, node, ctx, true), {slots: {'default': slot3(ctx)}}); return multi([b2, b4]); } }" @@ -80,7 +80,7 @@ exports[`Memo if no props, prevent renderings from above (work with simple html) return function template(ctx, node, key = \\"\\") { let b2 = text(ctx['state'].value); - let b4 = assign(component(\`Memo\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b4 = assign(component(\`Memo\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return multi([b2, b4]); } }" diff --git a/tests/misc/__snapshots__/portal.test.ts.snap b/tests/misc/__snapshots__/portal.test.ts.snap index 3e9f4561..7eac3a3c 100644 --- a/tests/misc/__snapshots__/portal.test.ts.snap +++ b/tests/misc/__snapshots__/portal.test.ts.snap @@ -28,7 +28,7 @@ exports[`Portal Portal composed with t-slot 2`] = ` } return function template(ctx, node, key = \\"\\") { - return assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + return assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } }" `; @@ -47,7 +47,7 @@ exports[`Portal Portal composed with t-slot 3`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Child\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Child\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -68,7 +68,7 @@ exports[`Portal basic use of portal 1`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -106,7 +106,7 @@ exports[`Portal conditional use of Portal (with sub Component) 2`] = ` let b2,b4; b2 = block2(); if (ctx['state'].hasPortal) { - b4 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + b4 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } return multi([b2, b4]); } @@ -131,7 +131,7 @@ exports[`Portal conditional use of Portal 1`] = ` let b2,b4; b2 = block2(); if (ctx['state'].hasPortal) { - b4 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + b4 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } return multi([b2, b4]); } @@ -169,7 +169,7 @@ exports[`Portal lifecycle hooks of portal sub component are properly called 2`] return function template(ctx, node, key = \\"\\") { let b3; if (ctx['state'].hasChild) { - b3 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + b3 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); } return block1([], [b3]); } @@ -196,7 +196,7 @@ exports[`Portal portal could have dynamically no content 1`] = ` } return function template(ctx, node, key = \\"\\") { - let b4 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b4 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b4]); } }" @@ -231,7 +231,7 @@ exports[`Portal portal destroys on crash 2`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -266,7 +266,7 @@ exports[`Portal portal with child and props 2`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -295,7 +295,7 @@ exports[`Portal portal with dynamic body 1`] = ` } return function template(ctx, node, key = \\"\\") { - let b5 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b5 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b5]); } }" @@ -319,7 +319,7 @@ exports[`Portal portal with many children 1`] = ` } return function template(ctx, node, key = \\"\\") { - let b5 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b5 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b5]); } }" @@ -343,7 +343,7 @@ exports[`Portal portal with no content 1`] = ` } return function template(ctx, node, key = \\"\\") { - let b4 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b4 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b4]); } }" @@ -363,7 +363,7 @@ exports[`Portal portal with only text as content 1`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -384,7 +384,7 @@ exports[`Portal portal with target not in dom 1`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Portal\`, {target: '#does-not-exist'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Portal\`, {target: '#does-not-exist'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -418,7 +418,7 @@ exports[`Portal portal's parent's env is not polluted 2`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -439,7 +439,7 @@ exports[`Portal with target in template (after portal) 1`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Portal\`, {target: '#local-target'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Portal\`, {target: '#local-target'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -460,7 +460,7 @@ exports[`Portal with target in template (before portal) 1`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Portal\`, {target: '#local-target'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Portal\`, {target: '#local-target'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -481,7 +481,7 @@ exports[`Portal: Props validation target is mandatory 1`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Portal\`, {}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Portal\`, {}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -502,7 +502,7 @@ exports[`Portal: Props validation target is not list 1`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Portal\`, {target: ['body']}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Portal\`, {target: ['body']}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" @@ -537,7 +537,7 @@ exports[`Portal: UI/UX focus is kept across re-renders 2`] = ` } return function template(ctx, node, key = \\"\\") { - let b3 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx), {slots: {'default': slot2(ctx)}}); + let b3 = assign(component(\`Portal\`, {target: '#outside'}, key + \`__1\`, node, ctx, true), {slots: {'default': slot2(ctx)}}); return block1([], [b3]); } }" diff --git a/tests/reactivity.test.ts b/tests/reactivity.test.ts index e74c0e46..3f0f4ad8 100644 --- a/tests/reactivity.test.ts +++ b/tests/reactivity.test.ts @@ -1510,7 +1510,7 @@ describe("Reactivity: useState", () => { expect([...steps]).toEqual(["list"]); await nextTick(); expect(fixture.innerHTML).toBe("
3
Total: 3 Count: 1
"); - expect([...steps]).toEqual(["list", "quantity1"]); + expect([...steps]).toEqual(["list"]); steps.clear(); secondQuantity.quantity = 2;