diff --git a/.changeset/clear-numbers-call.md b/.changeset/clear-numbers-call.md new file mode 100644 index 0000000000..bff19ec1a0 --- /dev/null +++ b/.changeset/clear-numbers-call.md @@ -0,0 +1,23 @@ +--- +"@lynx-js/react": patch +--- + +During hydration, replace update with insert + remove for same-type `` with different `item-key` so the Lynx Engine detects changes. + +```html +Hydrate List B into List A: + +List A: + + hello + world + + +List B: + + hello + world + +``` + +Previously this case was hydrated as an update; it is now emitted as insert + remove to ensure SDK detection. diff --git a/packages/react/runtime/__test__/list.test.jsx b/packages/react/runtime/__test__/list.test.jsx index 4162a77e5a..c9136f9828 100644 --- a/packages/react/runtime/__test__/list.test.jsx +++ b/packages/react/runtime/__test__/list.test.jsx @@ -1313,6 +1313,127 @@ describe('list reload', () => { , ); + it('For same-type list-item with different item-key, do an insert + remove so the SDK detects it.', () => { + const b = new SnapshotInstance(s1); + b.ensureElements(); + const root = b.__element_root; + + const s3 = __SNAPSHOT__( + + World + , + ); + + const d1 = new SnapshotInstance(s3); // a + const d2 = new SnapshotInstance(s3); // b + const d3 = new SnapshotInstance(s3); // c + const d4 = new SnapshotInstance(s3); // d + + d1.setAttribute(0, { 'item-key': 'a' }); + d2.setAttribute(0, { 'item-key': 'b' }); + d3.setAttribute(0, { 'item-key': 'c' }); + d4.setAttribute(0, { 'item-key': 'd' }); + b.insertBefore(d1); + b.insertBefore(d2); + b.insertBefore(d3); + b.insertBefore(d4); + + __pendingListUpdates.flush(); + + const bb = new SnapshotInstance(s1); + { + const d1 = new SnapshotInstance(s3); // a1 + const d2 = new SnapshotInstance(s3); // b1 + const d3 = new SnapshotInstance(s3); // c1 + const d4 = new SnapshotInstance(s3); // d1 + d1.setAttribute(0, { 'item-key': 'a1' }); + d2.setAttribute(0, { 'item-key': 'b1' }); + d3.setAttribute(0, { 'item-key': 'c1' }); + d4.setAttribute(0, { 'item-key': 'd1' }); + bb.insertBefore(d1); + bb.insertBefore(d2); + bb.insertBefore(d3); + bb.insertBefore(d4); + } + + hydrate(b, bb); + b.unRenderElements(); + + expect(root).toMatchInlineSnapshot(` + + + + + + + `); + }); + it('list-item with same type - remove', () => { const b = new SnapshotInstance(s1); b.ensureElements(); @@ -1359,15 +1480,15 @@ describe('list reload', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_35", + "type": "__Card__:__snapshot_a94a8_test_36", }, { "position": 1, - "type": "__Card__:__snapshot_a94a8_test_35", + "type": "__Card__:__snapshot_a94a8_test_36", }, { "position": 2, - "type": "__Card__:__snapshot_a94a8_test_35", + "type": "__Card__:__snapshot_a94a8_test_36", }, ], "removeAction": [], @@ -1404,15 +1525,15 @@ describe('list reload', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_35", + "type": "__Card__:__snapshot_a94a8_test_36", }, { "position": 1, - "type": "__Card__:__snapshot_a94a8_test_35", + "type": "__Card__:__snapshot_a94a8_test_36", }, { "position": 2, - "type": "__Card__:__snapshot_a94a8_test_35", + "type": "__Card__:__snapshot_a94a8_test_36", }, ], "removeAction": [], @@ -1429,7 +1550,7 @@ describe('list reload', () => { "insertAction": [ { "position": 2, - "type": "__Card__:__snapshot_a94a8_test_35", + "type": "__Card__:__snapshot_a94a8_test_36", }, ], "removeAction": [], @@ -1459,10 +1580,15 @@ describe('list reload', () => { , ); - const d1 = new SnapshotInstance(s3); - const d2 = new SnapshotInstance(s3); - const d3 = new SnapshotInstance(s4); - const d4 = new SnapshotInstance(s3); + const d1 = new SnapshotInstance(s3); // a + const d2 = new SnapshotInstance(s3); // b + const d3 = new SnapshotInstance(s4); // c + const d4 = new SnapshotInstance(s3); // d + + d1.setAttribute(0, { 'item-key': 'a' }); + d2.setAttribute(0, { 'item-key': 'b' }); + d3.setAttribute(0, { 'item-key': 'c' }); + d4.setAttribute(0, { 'item-key': 'd' }); b.insertBefore(d1); b.insertBefore(d2); b.insertBefore(d3); @@ -1472,10 +1598,14 @@ describe('list reload', () => { const bb = new SnapshotInstance(s1); { - const d1 = new SnapshotInstance(s3); - const d2 = new SnapshotInstance(s4); - const d3 = new SnapshotInstance(s3); - const d4 = new SnapshotInstance(s3); + const d1 = new SnapshotInstance(s3); // a + const d2 = new SnapshotInstance(s4); // c + const d3 = new SnapshotInstance(s3); // b + const d4 = new SnapshotInstance(s3); // d + d1.setAttribute(0, { 'item-key': 'a' }); + d2.setAttribute(0, { 'item-key': 'c' }); + d3.setAttribute(0, { 'item-key': 'b' }); + d4.setAttribute(0, { 'item-key': 'd' }); bb.insertBefore(d1); bb.insertBefore(d2); bb.insertBefore(d3); @@ -1499,20 +1629,24 @@ describe('list reload', () => { { "insertAction": [ { + "item-key": "a", "position": 0, - "type": "__Card__:__snapshot_a94a8_test_36", + "type": "__Card__:__snapshot_a94a8_test_37", }, { + "item-key": "b", "position": 1, - "type": "__Card__:__snapshot_a94a8_test_36", + "type": "__Card__:__snapshot_a94a8_test_37", }, { + "item-key": "c", "position": 2, - "type": "__Card__:__snapshot_a94a8_test_37", + "type": "__Card__:__snapshot_a94a8_test_38", }, { + "item-key": "d", "position": 3, - "type": "__Card__:__snapshot_a94a8_test_36", + "type": "__Card__:__snapshot_a94a8_test_37", }, ], "removeAction": [], @@ -1521,8 +1655,9 @@ describe('list reload', () => { { "insertAction": [ { + "item-key": "b", "position": 2, - "type": "__Card__:__snapshot_a94a8_test_36", + "type": "__Card__:__snapshot_a94a8_test_37", }, ], "removeAction": [ @@ -1588,15 +1723,15 @@ describe('list reload', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_38", + "type": "__Card__:__snapshot_a94a8_test_39", }, { "position": 1, - "type": "__Card__:__snapshot_a94a8_test_38", + "type": "__Card__:__snapshot_a94a8_test_39", }, { "position": 2, - "type": "__Card__:__snapshot_a94a8_test_38", + "type": "__Card__:__snapshot_a94a8_test_39", }, ], "removeAction": [], @@ -1679,19 +1814,19 @@ describe('list reload', () => { "full-span": true, "item-key": "1", "position": 0, - "type": "__Card__:__snapshot_a94a8_test_39", + "type": "__Card__:__snapshot_a94a8_test_40", }, { "full-span": true, "item-key": "2", "position": 1, - "type": "__Card__:__snapshot_a94a8_test_39", + "type": "__Card__:__snapshot_a94a8_test_40", }, { "full-span": true, "item-key": "3", "position": 2, - "type": "__Card__:__snapshot_a94a8_test_39", + "type": "__Card__:__snapshot_a94a8_test_40", }, ], "removeAction": [], @@ -1707,7 +1842,7 @@ describe('list reload', () => { "full-span": false, "item-key": "2", "to": 1, - "type": "__Card__:__snapshot_a94a8_test_39", + "type": "__Card__:__snapshot_a94a8_test_40", }, ], }, @@ -1795,19 +1930,19 @@ describe('list reload', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_40", + "type": "__Card__:__snapshot_a94a8_test_41", }, { "position": 1, - "type": "__Card__:__snapshot_a94a8_test_40", + "type": "__Card__:__snapshot_a94a8_test_41", }, { "position": 2, - "type": "__Card__:__snapshot_a94a8_test_40", + "type": "__Card__:__snapshot_a94a8_test_41", }, { "position": 3, - "type": "__Card__:__snapshot_a94a8_test_40", + "type": "__Card__:__snapshot_a94a8_test_41", }, ], "removeAction": [], @@ -1817,7 +1952,7 @@ describe('list reload', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_41", + "type": "__Card__:__snapshot_a94a8_test_42", }, ], "removeAction": [ @@ -1876,19 +2011,19 @@ describe('list reload', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_40", + "type": "__Card__:__snapshot_a94a8_test_41", }, { "position": 1, - "type": "__Card__:__snapshot_a94a8_test_40", + "type": "__Card__:__snapshot_a94a8_test_41", }, { "position": 2, - "type": "__Card__:__snapshot_a94a8_test_40", + "type": "__Card__:__snapshot_a94a8_test_41", }, { "position": 3, - "type": "__Card__:__snapshot_a94a8_test_40", + "type": "__Card__:__snapshot_a94a8_test_41", }, ], "removeAction": [], @@ -1898,7 +2033,7 @@ describe('list reload', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_41", + "type": "__Card__:__snapshot_a94a8_test_42", }, ], "removeAction": [ @@ -2038,15 +2173,15 @@ describe('list bug', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_46", + "type": "__Card__:__snapshot_a94a8_test_47", }, { "position": 1, - "type": "__Card__:__snapshot_a94a8_test_46", + "type": "__Card__:__snapshot_a94a8_test_47", }, { "position": 2, - "type": "__Card__:__snapshot_a94a8_test_46", + "type": "__Card__:__snapshot_a94a8_test_47", }, ], "removeAction": [], @@ -2055,19 +2190,19 @@ describe('list bug', () => { "flush": false, "from": 0, "to": 0, - "type": "__Card__:__snapshot_a94a8_test_46", + "type": "__Card__:__snapshot_a94a8_test_47", }, { "flush": false, "from": 1, "to": 1, - "type": "__Card__:__snapshot_a94a8_test_46", + "type": "__Card__:__snapshot_a94a8_test_47", }, { "flush": false, "from": 2, "to": 2, - "type": "__Card__:__snapshot_a94a8_test_46", + "type": "__Card__:__snapshot_a94a8_test_47", }, ], }, @@ -2085,7 +2220,7 @@ describe('list bug', () => { "insertAction": [ { "position": 2, - "type": "__Card__:__snapshot_a94a8_test_46", + "type": "__Card__:__snapshot_a94a8_test_47", }, ], "removeAction": [ @@ -2096,19 +2231,19 @@ describe('list bug', () => { "flush": false, "from": 0, "to": 0, - "type": "__Card__:__snapshot_a94a8_test_46", + "type": "__Card__:__snapshot_a94a8_test_47", }, { "flush": false, "from": 1, "to": 1, - "type": "__Card__:__snapshot_a94a8_test_46", + "type": "__Card__:__snapshot_a94a8_test_47", }, { "flush": false, "from": 2, "to": 2, - "type": "__Card__:__snapshot_a94a8_test_46", + "type": "__Card__:__snapshot_a94a8_test_47", }, ], }, @@ -2133,13 +2268,13 @@ describe('list bug', () => { "flush": false, "from": 0, "to": 0, - "type": "__Card__:__snapshot_a94a8_test_46", + "type": "__Card__:__snapshot_a94a8_test_47", }, { "flush": false, "from": 1, "to": 1, - "type": "__Card__:__snapshot_a94a8_test_46", + "type": "__Card__:__snapshot_a94a8_test_47", }, ], }, @@ -2221,21 +2356,21 @@ describe('list-item JSXSpread', () => { "item-key": "1", "position": 0, "recyclable": true, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, { "full-span": true, "item-key": "2", "position": 1, "recyclable": true, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, { "full-span": true, "item-key": "3", "position": 2, "recyclable": true, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, ], "removeAction": [], @@ -2252,7 +2387,7 @@ describe('list-item JSXSpread', () => { "item-key": "1", "recyclable": false, "to": 0, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, { "flush": false, @@ -2261,7 +2396,7 @@ describe('list-item JSXSpread', () => { "item-key": "2", "recyclable": false, "to": 1, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, { "flush": false, @@ -2270,7 +2405,7 @@ describe('list-item JSXSpread', () => { "item-key": "3", "recyclable": false, "to": 2, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, ], }, @@ -2300,21 +2435,21 @@ describe('list-item JSXSpread', () => { "item-key": "1", "position": 0, "recyclable": true, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, { "full-span": true, "item-key": "2", "position": 1, "recyclable": true, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, { "full-span": true, "item-key": "3", "position": 2, "recyclable": true, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, ], "removeAction": [], @@ -2331,7 +2466,7 @@ describe('list-item JSXSpread', () => { "item-key": "1", "recyclable": false, "to": 0, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, { "flush": false, @@ -2340,7 +2475,7 @@ describe('list-item JSXSpread', () => { "item-key": "2", "recyclable": false, "to": 1, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, { "flush": false, @@ -2349,7 +2484,7 @@ describe('list-item JSXSpread', () => { "item-key": "3", "recyclable": false, "to": 2, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, ], }, @@ -2390,21 +2525,21 @@ describe('list-item JSXSpread', () => { "item-key": "1", "position": 0, "recyclable": true, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, { "full-span": true, "item-key": "2", "position": 1, "recyclable": true, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, { "full-span": true, "item-key": "3", "position": 2, "recyclable": true, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, ], "removeAction": [], @@ -2421,7 +2556,7 @@ describe('list-item JSXSpread', () => { "item-key": "1", "recyclable": false, "to": 0, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, { "flush": false, @@ -2430,7 +2565,7 @@ describe('list-item JSXSpread', () => { "item-key": "2", "recyclable": false, "to": 1, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, { "flush": false, @@ -2439,7 +2574,7 @@ describe('list-item JSXSpread', () => { "item-key": "3", "recyclable": false, "to": 2, - "type": "__Card__:__snapshot_a94a8_test_48", + "type": "__Card__:__snapshot_a94a8_test_49", }, ], }, @@ -2562,7 +2697,7 @@ describe('list-item with platform info attributes', () => { "reuse-identifier": "A", "sticky-bottom": false, "sticky-top": true, - "type": "__Card__:__snapshot_a94a8_test_50", + "type": "__Card__:__snapshot_a94a8_test_51", }, { "estimated-height": 100, @@ -2575,7 +2710,7 @@ describe('list-item with platform info attributes', () => { "reuse-identifier": "A", "sticky-bottom": false, "sticky-top": false, - "type": "__Card__:__snapshot_a94a8_test_50", + "type": "__Card__:__snapshot_a94a8_test_51", }, { "estimated-height": 100, @@ -2588,7 +2723,7 @@ describe('list-item with platform info attributes', () => { "reuse-identifier": "A", "sticky-bottom": true, "sticky-top": false, - "type": "__Card__:__snapshot_a94a8_test_50", + "type": "__Card__:__snapshot_a94a8_test_51", }, ], "removeAction": [], @@ -2625,7 +2760,7 @@ describe('list-item with platform info attributes', () => { "reuse-identifier": "A", "sticky-bottom": false, "sticky-top": true, - "type": "__Card__:__snapshot_a94a8_test_50", + "type": "__Card__:__snapshot_a94a8_test_51", }, { "estimated-height": 100, @@ -2638,7 +2773,7 @@ describe('list-item with platform info attributes', () => { "reuse-identifier": "A", "sticky-bottom": false, "sticky-top": false, - "type": "__Card__:__snapshot_a94a8_test_50", + "type": "__Card__:__snapshot_a94a8_test_51", }, { "estimated-height": 100, @@ -2651,7 +2786,7 @@ describe('list-item with platform info attributes', () => { "reuse-identifier": "A", "sticky-bottom": true, "sticky-top": false, - "type": "__Card__:__snapshot_a94a8_test_50", + "type": "__Card__:__snapshot_a94a8_test_51", }, ], "removeAction": [], @@ -3126,7 +3261,7 @@ describe('list-item with "defer" attribute', () => { { "item-key": "1", "position": 0, - "type": "__Card__:__snapshot_a94a8_test_54", + "type": "__Card__:__snapshot_a94a8_test_55", }, ], "removeAction": [], @@ -3163,7 +3298,7 @@ describe('list-item with "defer" attribute', () => { { "item-key": "1", "position": 0, - "type": "__Card__:__snapshot_a94a8_test_54", + "type": "__Card__:__snapshot_a94a8_test_55", }, ], "removeAction": [], @@ -3256,17 +3391,17 @@ describe('list-item with "defer" attribute', () => { { "item-key": "0", "position": 0, - "type": "__Card__:__snapshot_a94a8_test_59", + "type": "__Card__:__snapshot_a94a8_test_60", }, { "item-key": "1", "position": 1, - "type": "__Card__:__snapshot_a94a8_test_60", + "type": "__Card__:__snapshot_a94a8_test_61", }, { "item-key": "2", "position": 2, - "type": "__Card__:__snapshot_a94a8_test_61", + "type": "__Card__:__snapshot_a94a8_test_62", }, ], "removeAction": [], @@ -3339,17 +3474,17 @@ describe('list-item with "defer" attribute', () => { { "item-key": "0", "position": 0, - "type": "__Card__:__snapshot_a94a8_test_59", + "type": "__Card__:__snapshot_a94a8_test_60", }, { "item-key": "1", "position": 1, - "type": "__Card__:__snapshot_a94a8_test_60", + "type": "__Card__:__snapshot_a94a8_test_61", }, { "item-key": "2", "position": 2, - "type": "__Card__:__snapshot_a94a8_test_61", + "type": "__Card__:__snapshot_a94a8_test_62", }, ], "removeAction": [], @@ -3420,17 +3555,17 @@ describe('list-item with "defer" attribute', () => { { "item-key": "0", "position": 0, - "type": "__Card__:__snapshot_a94a8_test_64", + "type": "__Card__:__snapshot_a94a8_test_65", }, { "item-key": "1", "position": 1, - "type": "__Card__:__snapshot_a94a8_test_64", + "type": "__Card__:__snapshot_a94a8_test_65", }, { "item-key": "2", "position": 2, - "type": "__Card__:__snapshot_a94a8_test_64", + "type": "__Card__:__snapshot_a94a8_test_65", }, ], "removeAction": [], @@ -3467,17 +3602,17 @@ describe('list-item with "defer" attribute', () => { { "item-key": "0", "position": 0, - "type": "__Card__:__snapshot_a94a8_test_64", + "type": "__Card__:__snapshot_a94a8_test_65", }, { "item-key": "1", "position": 1, - "type": "__Card__:__snapshot_a94a8_test_64", + "type": "__Card__:__snapshot_a94a8_test_65", }, { "item-key": "2", "position": 2, - "type": "__Card__:__snapshot_a94a8_test_64", + "type": "__Card__:__snapshot_a94a8_test_65", }, ], "removeAction": [], @@ -3526,17 +3661,17 @@ describe('list-item with "defer" attribute', () => { { "item-key": "0", "position": 0, - "type": "__Card__:__snapshot_a94a8_test_64", + "type": "__Card__:__snapshot_a94a8_test_65", }, { "item-key": "1", "position": 1, - "type": "__Card__:__snapshot_a94a8_test_64", + "type": "__Card__:__snapshot_a94a8_test_65", }, { "item-key": "2", "position": 2, - "type": "__Card__:__snapshot_a94a8_test_64", + "type": "__Card__:__snapshot_a94a8_test_65", }, ], "removeAction": [], @@ -3668,15 +3803,15 @@ describe('nested list', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_69", + "type": "__Card__:__snapshot_a94a8_test_70", }, { "position": 1, - "type": "__Card__:__snapshot_a94a8_test_69", + "type": "__Card__:__snapshot_a94a8_test_70", }, { "position": 2, - "type": "__Card__:__snapshot_a94a8_test_69", + "type": "__Card__:__snapshot_a94a8_test_70", }, ], "removeAction": [], @@ -3688,7 +3823,7 @@ describe('nested list', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_70", + "type": "__Card__:__snapshot_a94a8_test_71", }, ], "removeAction": [], @@ -3700,7 +3835,7 @@ describe('nested list', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_70", + "type": "__Card__:__snapshot_a94a8_test_71", }, ], "removeAction": [], @@ -3712,7 +3847,7 @@ describe('nested list', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_70", + "type": "__Card__:__snapshot_a94a8_test_71", }, ], "removeAction": [], @@ -3732,7 +3867,7 @@ describe('nested list', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_70", + "type": "__Card__:__snapshot_a94a8_test_71", }, ], "removeAction": [], @@ -3744,7 +3879,7 @@ describe('nested list', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_70", + "type": "__Card__:__snapshot_a94a8_test_71", }, ], "removeAction": [], @@ -3756,7 +3891,7 @@ describe('nested list', () => { "insertAction": [ { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_70", + "type": "__Card__:__snapshot_a94a8_test_71", }, ], "removeAction": [], @@ -3795,15 +3930,15 @@ describe('nested list', () => { "insertAction": Array [ Object { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_69", + "type": "__Card__:__snapshot_a94a8_test_70", }, Object { "position": 1, - "type": "__Card__:__snapshot_a94a8_test_69", + "type": "__Card__:__snapshot_a94a8_test_70", }, Object { "position": 2, - "type": "__Card__:__snapshot_a94a8_test_69", + "type": "__Card__:__snapshot_a94a8_test_70", }, ], "removeAction": Array [], @@ -3825,7 +3960,7 @@ describe('nested list', () => { "insertAction": Array [ Object { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_70", + "type": "__Card__:__snapshot_a94a8_test_71", }, ], "removeAction": Array [], @@ -3856,7 +3991,7 @@ describe('nested list', () => { "insertAction": Array [ Object { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_70", + "type": "__Card__:__snapshot_a94a8_test_71", }, ], "removeAction": Array [], @@ -3887,7 +4022,7 @@ describe('nested list', () => { "insertAction": Array [ Object { "position": 0, - "type": "__Card__:__snapshot_a94a8_test_70", + "type": "__Card__:__snapshot_a94a8_test_71", }, ], "removeAction": Array [], diff --git a/packages/react/runtime/src/backgroundSnapshot.ts b/packages/react/runtime/src/backgroundSnapshot.ts index 6f72835dc0..b1c6a51e22 100644 --- a/packages/react/runtime/src/backgroundSnapshot.ts +++ b/packages/react/runtime/src/backgroundSnapshot.ts @@ -471,6 +471,8 @@ export function hydrate( (a, b) => { helper(a, b); }, + // Should be `false` in hydrate as SerializedSnapshotInstance has no item-key + false, ); diffArrayAction( beforeChildNodes, diff --git a/packages/react/runtime/src/hydrate.ts b/packages/react/runtime/src/hydrate.ts index 322fbe6f91..077b514663 100644 --- a/packages/react/runtime/src/hydrate.ts +++ b/packages/react/runtime/src/hydrate.ts @@ -5,10 +5,13 @@ import { componentAtIndexFactory, enqueueComponentFactory, gRecycleMap, gSignMap } from './list.js'; import { __pendingListUpdates } from './pendingListUpdates.js'; import { DynamicPartType } from './snapshot/dynamicPartType.js'; +import type { PlatformInfo } from './snapshot/platformInfo.js'; import { unref } from './snapshot/ref.js'; import type { SnapshotInstance } from './snapshot.js'; import { isEmptyObject } from './utils.js'; +const UNREACHABLE_ITEM_KEY_NOT_FOUND = 'UNREACHABLE_ITEM_KEY_NOT_FOUND'; + export interface DiffResult { $$diff: true; // insert No.j to new @@ -21,6 +24,7 @@ export interface DiffResult { export interface Typed { type: string; + __listItemPlatformInfo?: PlatformInfo; } export function isEmptyDiffResult(diffResult: DiffResult): boolean { @@ -34,6 +38,7 @@ export function diffArrayLepus( after: B[], isSameType: (a: A, b: B) => boolean, onDiffChildren: (a: A, b: B, oldIndex: number, newIndex: number) => void, + isListHasItemKey: boolean, ): DiffResult { let lastPlacedIndex = 0; const result: DiffResult = { @@ -46,12 +51,18 @@ export function diffArrayLepus( for (let i = 0; i < before.length; i++) { const node = before[i]!; - (beforeMap[node.type] ??= new Set()).add([node, i]); + const key = isListHasItemKey + ? node.__listItemPlatformInfo?.['item-key'] ?? UNREACHABLE_ITEM_KEY_NOT_FOUND + : node.type; + (beforeMap[key] ??= new Set()).add([node, i]); } for (let i = 0; i < after.length; i++) { const afterNode = after[i]!; - const beforeNodes = beforeMap[afterNode.type]; + const key = isListHasItemKey + ? afterNode.__listItemPlatformInfo?.['item-key'] ?? UNREACHABLE_ITEM_KEY_NOT_FOUND + : afterNode.type; + const beforeNodes = beforeMap[key]; let beforeNode: [A, number]; if ( @@ -258,6 +269,7 @@ export function hydrate(before: SnapshotInstance, after: SnapshotInstance, optio (a, b) => { hydrate(a, b, options); }, + false, ); diffArrayAction( beforeChildNodes, @@ -341,6 +353,7 @@ export function hydrate(before: SnapshotInstance, after: SnapshotInstance, optio } } }, + true, ); for (const i of diffResult.r) {