diff --git a/src/diff/children.js b/src/diff/children.js index 22b7a61c9c..b44d5168e8 100644 --- a/src/diff/children.js +++ b/src/diff/children.js @@ -303,14 +303,11 @@ function constructNewChildrenArray(newParentVNode, renderResult, oldChildren) { if (remainingOldChildren > newChildrenLength - skewedIndex) { skew += matchingIndex - skewedIndex; } else { - // ### Change from keyed: I think this was missing from the algo... skew--; } } else if (matchingIndex < skewedIndex) { if (matchingIndex == skewedIndex - 1) { skew = matchingIndex - skewedIndex; - } else { - skew = 0; } } else { skew = 0; @@ -429,7 +426,10 @@ function findMatchingIndex( if ( oldVNode === null || - (oldVNode && key == oldVNode.key && type === oldVNode.type) + (oldVNode && + key == oldVNode.key && + type === oldVNode.type && + (oldVNode._flags & MATCHED) === 0) ) { return skewedIndex; } else if (shouldSearch) { diff --git a/test/browser/render.test.js b/test/browser/render.test.js index 075b6ad39f..ae42ce2720 100644 --- a/test/browser/render.test.js +++ b/test/browser/render.test.js @@ -1357,6 +1357,133 @@ describe('render()', () => { expect(scratch.innerHTML).to.equal('
B
'); }); + it('should reconcile children in right order', () => { + let data = ['A', 'B', 'C', 'D', 'E']; + render( + , + scratch + ); + + expect(scratch.textContent).to.equal('ABCDE'); + + data = ['B', 'E', 'C', 'D']; + render( + , + scratch + ); + expect(scratch.textContent).to.equal('BECD'); + }); + + it('should reconcile children in right order #2', () => { + let data = ['A', 'B', 'C', 'D', 'E']; + render( + , + scratch + ); + + expect(scratch.textContent).to.equal('ABCDE'); + + data = ['B', 'E', 'D', 'C']; + render( + , + scratch + ); + expect(scratch.textContent).to.equal('BEDC'); + }); + + it('should reconcile children in right order #3', () => { + render( +
+

_A1

+

_A2

+

_A3

+

_A4

+

_A5

+

_A6

+

_A7

+

_A8

+
, + scratch + ); + + render( +
+

_B1

+

_B2

+

_B3

+

_B4

+

_B5

+

_B6

+

_B7

+

_B8

+
, + scratch + ); + + expect(serializeHtml(scratch)).to.equal( + '

_B1

_B2

_B3

_B4

_B5

_B6

_B7

_B8

' + ); + }); + + it('should reconcile children in right order #4', () => { + render( +
+

_A1

+

_A2

+
_A3
+

_A4

+

_A5

+
_A6
+

_A7

+

_A8

+
_A9
+

_A10

+

_A11

+
_A12
+
, + scratch + ); + + render( +
+

_B1

+

_B2

+

_B3

+

_B4

+

_B5

+

_B6

+

_B7

+

_B8

+

_B9

+

_B10

+

_B11

+

_B12

+

_B13

+
, + scratch + ); + + expect(serializeHtml(scratch)).to.equal( + '

_B1

_B2

_B3

_B4

_B5

_B6

_B7

_B8

_B9

_B10

_B11

_B12

_B13

' + ); + }); + it('should not crash or repeatedly add the same child when replacing a matched vnode with null (mixed dom-types)', () => { const B = () =>
B
;