Skip to content

Commit b7fabca

Browse files
authored
Merge pull request #7631 from QwikDev/v2-skip-rerender-component
fix: ensure components are only rendered when necessary
2 parents e38beed + 3949581 commit b7fabca

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

.changeset/pretty-trees-check.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: ensure components are only rendered when necessary

packages/qwik/src/core/client/vnode-diff.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1053,9 +1053,9 @@ export const vnode_diff = (
10531053
} else {
10541054
// We did not find the component, create it.
10551055
insertNewComponent(host, componentQRL, jsxProps);
1056+
shouldRender = true;
10561057
}
10571058
host = vNewNode as VirtualVNode;
1058-
shouldRender = true;
10591059
} else if (!hashesAreEqual || !jsxNode.key) {
10601060
insertNewComponent(host, componentQRL, jsxProps);
10611061
host = vNewNode as VirtualVNode;

packages/qwik/src/core/tests/component.spec.tsx

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,80 @@ describe.each([
227227
);
228228
});
229229

230+
it('should not rerender not changed component', async () => {
231+
(globalThis as any).componentExecuted = [];
232+
const Component1 = component$(() => {
233+
(globalThis as any).componentExecuted.push('Component1');
234+
const signal1 = useSignal(1);
235+
return (
236+
<div>
237+
<span>Component 1</span>
238+
{signal1.value}
239+
</div>
240+
);
241+
});
242+
const Component2 = component$(() => {
243+
(globalThis as any).componentExecuted.push('Component2');
244+
const signal2 = useSignal(2);
245+
return (
246+
<div>
247+
<span>Component 2</span>
248+
{signal2.value}
249+
</div>
250+
);
251+
});
252+
const Parent = component$(() => {
253+
(globalThis as any).componentExecuted.push('Parent');
254+
const show = useSignal(true);
255+
return (
256+
<main class="parent" onClick$={() => (show.value = false)}>
257+
{show.value && <Component1 />}
258+
<Component2 />
259+
</main>
260+
);
261+
});
262+
const { vNode, container } = await render(<Parent />, { debug });
263+
expect(vNode).toMatchVDOM(
264+
<Component ssr-required>
265+
<main class="parent">
266+
<Component ssr-required>
267+
<div>
268+
<span>Component 1</span>
269+
<Signal ssr-required>1</Signal>
270+
</div>
271+
</Component>
272+
<Component ssr-required>
273+
<div>
274+
<span>Component 2</span>
275+
<Signal ssr-required>2</Signal>
276+
</div>
277+
</Component>
278+
</main>
279+
</Component>
280+
);
281+
expect((globalThis as any).componentExecuted).toEqual(['Parent', 'Component1', 'Component2']);
282+
await trigger(container.element, 'main.parent', 'click');
283+
expect((globalThis as any).componentExecuted).toEqual([
284+
'Parent',
285+
'Component1',
286+
'Component2',
287+
'Parent',
288+
]);
289+
expect(vNode).toMatchVDOM(
290+
<Component ssr-required>
291+
<main class="parent">
292+
{''}
293+
<Component ssr-required>
294+
<div>
295+
<span>Component 2</span>
296+
<Signal ssr-required>2</Signal>
297+
</div>
298+
</Component>
299+
</main>
300+
</Component>
301+
);
302+
});
303+
230304
it('should remove children from component$', async () => {
231305
const log: string[] = [];
232306
const MyComp = component$((props: any) => {

0 commit comments

Comments
 (0)