Skip to content

Commit

Permalink
fix(child-diffing): Should shift keyed fragmented lists (#4448)
Browse files Browse the repository at this point in the history
* Should shift keyed fragmented lists

* cleanup old usage of oldDom
  • Loading branch information
JoviDeCroock authored Jul 19, 2024
1 parent 16c7fb7 commit f573891
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 8 deletions.
16 changes: 8 additions & 8 deletions src/diff/children.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,6 @@ export function diffChildren(
childVNode._flags & INSERT_VNODE ||
oldVNode._children === childVNode._children
) {
if (
oldDom &&
typeof childVNode.type == 'string' &&
// @ts-expect-error olDom should be present on a DOM node
!parentDom.contains(oldDom)
) {
oldDom = getDomSibling(oldVNode);
}
oldDom = insert(childVNode, oldDom, parentDom);
} else if (
typeof childVNode.type == 'function' &&
Expand Down Expand Up @@ -378,6 +370,14 @@ function insert(parentVNode, oldDom, parentDom) {

return oldDom;
} else if (parentVNode._dom != oldDom) {
if (
oldDom &&
parentVNode.type &&
// @ts-expect-error olDom should be present on a DOM node
!parentDom.contains(oldDom)
) {
oldDom = getDomSibling(parentVNode);
}
parentDom.insertBefore(parentVNode._dom, oldDom || null);
oldDom = parentVNode._dom;
}
Expand Down
54 changes: 54 additions & 0 deletions test/browser/render.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1689,4 +1689,58 @@ describe('render()', () => {
]);
clearLog();
});

it('should shift keyed lists with wrapping fragment-like children', () => {
const ItemA = ({ text }) => <div>A: {text}</div>;
const ItemB = ({ text }) => <div>B: {text}</div>;

const Item = ({ text, type }) => {
return type === 'B' ? <ItemB text={text} /> : <ItemA text={text} />;
};

let set;
class App extends Component {
constructor(props) {
super(props);
this.state = { items: a, mapping: mappingA };
set = (items, mapping) => {
this.setState({ items, mapping });
};
}

render() {
return (
<ul>
{this.state.items.map((key, i) => (
<Item key={key} type={this.state.mapping[i]} text={key} />
))}
</ul>
);
}
}

const a = ['4', '1', '2', '3'];
const mappingA = ['A', 'A', 'B', 'B'];
const b = ['1', '2', '4', '3'];
const mappingB = ['B', 'A', 'A', 'A'];
const c = ['4', '2', '1', '3'];
const mappingC = ['A', 'B', 'B', 'A'];

render(<App items={a} mapping={mappingA} />, scratch);
expect(scratch.innerHTML).to.equal(
'<ul><div>A: 4</div><div>A: 1</div><div>B: 2</div><div>B: 3</div></ul>'
);

set(b, mappingB);
rerender();
expect(scratch.innerHTML).to.equal(
'<ul><div>B: 1</div><div>A: 2</div><div>A: 4</div><div>A: 3</div></ul>'
);

set(c, mappingC);
rerender();
expect(scratch.innerHTML).to.equal(
'<ul><div>A: 4</div><div>B: 2</div><div>B: 1</div><div>A: 3</div></ul>'
);
});
});

0 comments on commit f573891

Please sign in to comment.