Skip to content

Commit

Permalink
fix(v2): component rerender with the same key and different props (#6208
Browse files Browse the repository at this point in the history
)

fix(v2): component rerender with the same prop and different props
  • Loading branch information
Varixo authored May 3, 2024
1 parent 80d2181 commit 0ce434d
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 10 deletions.
12 changes: 2 additions & 10 deletions packages/qwik/src/core/v2/client/vnode-diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1046,8 +1046,8 @@ function propsDiffer(src: Record<string, any>, dst: Record<string, any>): boolea
if (!src || !dst) {
return true;
}
let srcKeys = removeChildrenKey(Object.keys(src));
let dstKeys = removeChildrenKey(Object.keys(dst));
let srcKeys = Object.keys(src);
let dstKeys = Object.keys(dst);
if (srcKeys.length !== dstKeys.length) {
return true;
}
Expand All @@ -1063,14 +1063,6 @@ function propsDiffer(src: Record<string, any>, dst: Record<string, any>): boolea
return false;
}

function removeChildrenKey(keys: string[]): string[] {
const childrenIdx = keys.indexOf('children');
if (childrenIdx !== -1) {
keys.splice(childrenIdx, 1);
}
return keys;
}

/**
* If vnode is removed, it is necessary to release all subscriptions associated with it.
*
Expand Down
89 changes: 89 additions & 0 deletions packages/qwik/src/core/v2/component.unit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,95 @@ describe.each([
expect(document.querySelector('p')).toMatchDOM(<p>{'"<script></script>"'}</p>);
});

it('should rerender components with the same key and different props', async () => {
const Child = component$<{ value: number; active: boolean }>((props) => {
return (
<div>
Child {props.value}, active: {props.active ? 'true' : 'false'}
</div>
);
});

const Cmp = component$(() => {
const signal = useSignal(1);

const children = [1, 2];

return (
<div>
<button id="button-1" onClick$={() => (signal.value = 1)}>
1
</button>
<button id="button-2" onClick$={() => (signal.value = 2)}>
2
</button>

<>
{children.map((value) => {
return <Child key={value} value={value} active={signal.value === value} />;
})}
</>
</div>
);
});

const { vNode, document } = await render(<Cmp />, { debug });
await trigger(document.body, '#button-2', 'click');
expect(vNode).toMatchVDOM(
<Component>
<div>
<button id="button-1">1</button>
<button id="button-2">2</button>
<Fragment>
<Component>
<div>
{'Child '}
<Signal>{'1'}</Signal>
{', active: '}
<Signal>{'false'}</Signal>
</div>
</Component>
<Component>
<div>
{'Child '}
<Signal>{'2'}</Signal>
{', active: '}
<Signal>{'true'}</Signal>
</div>
</Component>
</Fragment>
</div>
</Component>
);
await trigger(document.body, '#button-1', 'click');
expect(vNode).toMatchVDOM(
<Component>
<div>
<button id="button-1">1</button>
<button id="button-2">2</button>
<Fragment>
<Component>
<div>
{'Child '}
<Signal>{'1'}</Signal>
{', active: '}
<Signal>{'true'}</Signal>
</div>
</Component>
<Component>
<div>
{'Child '}
<Signal>{'2'}</Signal>
{', active: '}
<Signal>{'false'}</Signal>
</div>
</Component>
</Fragment>
</div>
</Component>
);
});

describe('svg', () => {
it('should render svg', async () => {
const SvgComp = component$(() => {
Expand Down
1 change: 1 addition & 0 deletions packages/qwik/src/core/v2/shared/component-execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export const executeComponent2 = (
safeCall<JSXOutput, JSXOutput, JSXOutput>(
() => {
container.setHostProp(renderHost, SEQ_IDX_LOCAL, null);
container.setHostProp(renderHost, ELEMENT_PROPS, props);
return componentFn(props);
},
(jsx) => {
Expand Down

0 comments on commit 0ce434d

Please sign in to comment.