From 7b5b240f0c3697d95c64bcd43fe87139d3983d4f Mon Sep 17 00:00:00 2001 From: Jovi De Croock Date: Fri, 9 Aug 2024 12:10:03 +0200 Subject: [PATCH] Add stress test and another fix (#4472) --- src/diff/children.js | 16 +++++------ test/browser/render.test.js | 57 +++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/src/diff/children.js b/src/diff/children.js index e50ca1cef5..3c4b1edc89 100644 --- a/src/diff/children.js +++ b/src/diff/children.js @@ -299,7 +299,7 @@ function constructNewChildrenArray(newParentVNode, renderResult, oldChildren) { } } else if (matchingIndex !== skewedIndex) { if (matchingIndex == skewedIndex - 1) { - skew = matchingIndex - skewedIndex; + skew--; } else if (matchingIndex == skewedIndex + 1) { skew++; } else if (matchingIndex > skewedIndex) { @@ -316,8 +316,12 @@ function constructNewChildrenArray(newParentVNode, renderResult, oldChildren) { skew--; } } else if (matchingIndex < skewedIndex) { - // When our new position is in front of our old position than we increase the skew - skew++; + if (matchingIndex == skewedIndex - skew) { + skew -= matchingIndex - skewedIndex; + } else { + // When our new position is in front of our old position than we increase the skew + skew++; + } } // Move this VNode's DOM if the original index (matchingIndex) doesn't @@ -370,11 +374,7 @@ function insert(parentVNode, oldDom, parentDom) { return oldDom; } else if (parentVNode._dom != oldDom) { - if ( - oldDom && - parentVNode.type && - !parentDom.contains(oldDom) - ) { + if (oldDom && parentVNode.type && !parentDom.contains(oldDom)) { oldDom = getDomSibling(parentVNode); } parentDom.insertBefore(parentVNode._dom, oldDom || null); diff --git a/test/browser/render.test.js b/test/browser/render.test.js index bb2c2d4adb..da494113fb 100644 --- a/test/browser/render.test.js +++ b/test/browser/render.test.js @@ -1743,4 +1743,61 @@ describe('render()', () => { '' ); }); + + it('handle shuffled array children (moving to the front)', () => { + const App = ({ items }) => ( +
+ {items.map(key => ( +
{key}
+ ))} +
+ ); + + const a = ['0', '2', '7', '6', '1', '3', '5', '4']; + const b = ['1', '0', '6', '7', '5', '2', '4', '3']; + const c = ['0', '7', '2', '1', '3', '5', '6', '4']; + + render(, scratch); + expect(scratch.innerHTML).to.equal( + `
${a.map(n => `
${n}
`).join('')}
` + ); + + render(, scratch); + expect(scratch.innerHTML).to.equal( + `
${b.map(n => `
${n}
`).join('')}
` + ); + + render(, scratch); + expect(scratch.innerHTML).to.equal( + `
${c.map(n => `
${n}
`).join('')}
` + ); + }); + + it('handle shuffled (stress test)', () => { + function randomize(arr) { + for (let i = arr.length - 1; i > 0; i--) { + let j = Math.floor(Math.random() * (i + 1)); + [arr[i], arr[j]] = [arr[j], arr[i]]; + } + return arr; + } + + const App = ({ items }) => ( +
+ {items.map(key => ( +
{key}
+ ))} +
+ ); + + const a = Array.from({ length: 8 }).map((_, i) => `${i}`); + + for (let i = 0; i < 10000; i++) { + const aa = randomize(a); + render(, scratch); + expect(scratch.innerHTML).to.equal( + `
${aa.map(n => `
${n}
`).join('')}
` + ); + } + }); });