Skip to content

Commit

Permalink
fix: ordering issue with Component re-render (#4125)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoviDeCroock committed Sep 3, 2023
1 parent 317025f commit 7a3706a
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export function getDomSibling(vnode, childIndex) {
// Since updateParentDomPointers keeps _dom pointer correct,
// we can rely on _dom to tell us if this subtree contains a
// rendered DOM node, and what the first rendered DOM node is
return sibling._dom;
return sibling._nextDom || sibling._dom;
}
}

Expand Down
1 change: 1 addition & 0 deletions src/diff/children.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export function diffChildren(
oldVNode = oldChildren[i];
if (oldVNode && oldVNode.key == null && oldVNode._dom) {
if (oldVNode._dom == oldDom) {
oldVNode._parent = oldParentVNode;
oldDom = getDomSibling(oldVNode);
}

Expand Down
104 changes: 104 additions & 0 deletions test/browser/fragments.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,110 @@ describe('Fragment', () => {
expect(scratch.innerHTML).to.equal('<div>Hello</div>');
});

it('should preserve order for fragment switching', () => {
let set;
class Foo extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, data: null };
set = this.setState.bind(this);
}
render(props, { isLoading, data }) {
return (
<Fragment>
<div>HEADER</div>
{isLoading ? <div>Loading...</div> : null}
{data ? <div>Content: {data}</div> : null}
</Fragment>
);
}
}

render(<Foo />, scratch);
expect(scratch.innerHTML).to.equal(
'<div>HEADER</div><div>Loading...</div>'
);

set({ isLoading: false, data: 2 });
rerender();
expect(scratch.innerHTML).to.equal(
'<div>HEADER</div><div>Content: 2</div>'
);
});

it('should preserve order for nested fragment switching w/ child return', () => {
let set;
const Wrapper = ({ children }) => <Fragment>{children}</Fragment>;
class Foo extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, data: null };
set = this.setState.bind(this);
}
render(props, { isLoading, data }) {
return (
<Fragment>
<div>HEADER</div>
{isLoading ? <div>Loading...</div> : null}
{data ? <div>Content: {data}</div> : null}
</Fragment>
);
}
}

render(
<Wrapper>
<Foo />
</Wrapper>,
scratch
);
expect(scratch.innerHTML).to.equal(
'<div>HEADER</div><div>Loading...</div>'
);

set({ isLoading: false, data: 2 });
rerender();
expect(scratch.innerHTML).to.equal(
'<div>HEADER</div><div>Content: 2</div>'
);
});

it('should preserve order for nested fragment switching', () => {
let set;
const Wrapper = () => (
<Fragment>
<Foo />
</Fragment>
);
class Foo extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, data: null };
set = this.setState.bind(this);
}
render(props, { isLoading, data }) {
return (
<Fragment>
<div>HEADER</div>
{isLoading ? <div>Loading...</div> : null}
{data ? <div>Content: {data}</div> : null}
</Fragment>
);
}
}

render(<Wrapper />, scratch);
expect(scratch.innerHTML).to.equal(
'<div>HEADER</div><div>Loading...</div>'
);

set({ isLoading: false, data: 2 });
rerender();
expect(scratch.innerHTML).to.equal(
'<div>HEADER</div><div>Content: 2</div>'
);
});

it('should preserve state with reordering in multiple levels', () => {
function Foo({ condition }) {
return condition ? (
Expand Down

0 comments on commit 7a3706a

Please sign in to comment.