Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/diff/children.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ function constructNewChildrenArray(
remainingOldChildren
));

oldVNode = NULL;
if (matchingIndex != -1) {
oldVNode = oldChildren[matchingIndex];
remainingOldChildren--;
Expand Down
235 changes: 134 additions & 101 deletions test/browser/keys.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,11 @@ describe('keys', () => {
render({ children, busy }) {
return (
<div class={busy ? 'busy' : ''}>
{children && children.length
? children
: <div class="busy-placeholder" />}
{children && children.length ? (
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, odd that the pre-commit reformats this

children
) : (
<div class="busy-placeholder" />
)}
<div class="indicator">
<div>indicator</div>
<div>indicator</div>
Expand Down Expand Up @@ -566,19 +568,21 @@ describe('keys', () => {
let Stateful2MovedRef;

function Foo({ moved }) {
return moved
? <div>
<div>1</div>
<Stateful1 key="c" ref={c => (Stateful1MovedRef = c)} />
<div>2</div>
<Stateful2 key="d" ref={c => (Stateful2MovedRef = c)} />
</div>
: <div>
<div>1</div>
<Stateful1 key="a" ref={c => (Stateful1Ref = c)} />
<div>2</div>
<Stateful2 key="b" ref={c => (Stateful2Ref = c)} />
</div>;
return moved ? (
<div>
<div>1</div>
<Stateful1 key="c" ref={c => (Stateful1MovedRef = c)} />
<div>2</div>
<Stateful2 key="d" ref={c => (Stateful2MovedRef = c)} />
</div>
) : (
<div>
<div>1</div>
<Stateful1 key="a" ref={c => (Stateful1Ref = c)} />
<div>2</div>
<Stateful2 key="b" ref={c => (Stateful2Ref = c)} />
</div>
);
}

const expectedHtml = div([
Expand Down Expand Up @@ -635,31 +639,27 @@ describe('keys', () => {
let Stateful2MovedRef;

function Foo({ moved }) {
return moved
? <div>
<div>1</div>
<Stateful2
key="b"
ref={c => (c ? (Stateful2MovedRef = c) : undefined)}
/>
<div>2</div>
<Stateful1
key="a"
ref={c => (c ? (Stateful1MovedRef = c) : undefined)}
/>
</div>
: <div>
<div>1</div>
<Stateful1
key="a"
ref={c => (c ? (Stateful1Ref = c) : undefined)}
/>
<div>2</div>
<Stateful2
key="b"
ref={c => (c ? (Stateful2Ref = c) : undefined)}
/>
</div>;
return moved ? (
<div>
<div>1</div>
<Stateful2
key="b"
ref={c => (c ? (Stateful2MovedRef = c) : undefined)}
/>
<div>2</div>
<Stateful1
key="a"
ref={c => (c ? (Stateful1MovedRef = c) : undefined)}
/>
</div>
) : (
<div>
<div>1</div>
<Stateful1 key="a" ref={c => (c ? (Stateful1Ref = c) : undefined)} />
<div>2</div>
<Stateful2 key="b" ref={c => (c ? (Stateful2Ref = c) : undefined)} />
</div>
);
}

const htmlForFalse = div([
Expand Down Expand Up @@ -841,19 +841,21 @@ describe('keys', () => {
let Stateful2MovedRef;

function Foo({ unkeyed }) {
return unkeyed
? <div>
<div>1</div>
<Stateful1 ref={c => (Stateful2MovedRef = c)} />
<div>2</div>
<Stateful2 ref={c => (Stateful1MovedRef = c)} />
</div>
: <div>
<div>1</div>
<Stateful1 key="a" ref={c => (Stateful1Ref = c)} />
<div>2</div>
<Stateful2 key="b" ref={c => (Stateful2Ref = c)} />
</div>;
return unkeyed ? (
<div>
<div>1</div>
<Stateful1 ref={c => (Stateful2MovedRef = c)} />
<div>2</div>
<Stateful2 ref={c => (Stateful1MovedRef = c)} />
</div>
) : (
<div>
<div>1</div>
<Stateful1 key="a" ref={c => (Stateful1Ref = c)} />
<div>2</div>
<Stateful2 key="b" ref={c => (Stateful2Ref = c)} />
</div>
);
}

const expectedHtml = div([
Expand Down Expand Up @@ -1007,18 +1009,20 @@ describe('keys', () => {
}

const App = props => {
return props.y === '2'
? <div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>
: <div>
{null}
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>;
return props.y === '2' ? (
<div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>
) : (
<div>
{null}
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>
);
};

render(<App y="1" />, scratch);
Expand All @@ -1040,17 +1044,19 @@ describe('keys', () => {
}

const App = props => {
return props.y === '1'
? <div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>
: <div>
<Comp key={1} i={1} />
{null}
<Comp key={3} i={3} />
</div>;
return props.y === '1' ? (
<div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>
) : (
<div>
<Comp key={1} i={1} />
{null}
<Comp key={3} i={3} />
</div>
);
};

render(<App y="1" />, scratch);
Expand Down Expand Up @@ -1080,18 +1086,20 @@ describe('keys', () => {
}

const App = props => {
return props.y === '2'
? <div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>
: <div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
{null}
<Comp key={3} i={3} />
</div>;
return props.y === '2' ? (
<div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>
) : (
<div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
{null}
<Comp key={3} i={3} />
</div>
);
};

render(<App y="1" />, scratch);
Expand All @@ -1113,18 +1121,20 @@ describe('keys', () => {
}

const App = props => {
return props.y === '2'
? <div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>
: <div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
{null}
</div>;
return props.y === '2' ? (
<div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>
) : (
<div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
{null}
</div>
);
};

render(<App y="1" />, scratch);
Expand All @@ -1133,4 +1143,27 @@ describe('keys', () => {
render(<App y="2" />, scratch);
expect(actions).to.deep.equal(['mounted 1', 'mounted 2', 'mounted 3']);
});

// Issue #4973: Test growing list diff
it('should correctly diff a growing list of keyed children', () => {
let values = [0, 1, 2, 3, 4];

render(<List values={values} />, scratch);
expect(scratch.textContent).to.equal('01234');

values = [2, 3, 4, 5, 6];
clearLog();

render(<List values={values} />, scratch);
expect(scratch.textContent).to.equal('23456');

expect(getLog()).to.deep.equal([
'<li>0.remove()',
'<li>1.remove()',
'<li>.appendChild(#text)',
'<ol>234.appendChild(<li>5)',
'<li>.appendChild(#text)',
'<ol>2345.appendChild(<li>6)'
]);
});
});
Loading