diff --git a/.changeset/early-crabs-lie.md b/.changeset/early-crabs-lie.md new file mode 100644 index 0000000000..f2d05b072a --- /dev/null +++ b/.changeset/early-crabs-lie.md @@ -0,0 +1,5 @@ +--- +"@lynx-js/react": patch +--- + +Fixed blank screen issues with nested lists. Lazily created nested lists were being flushed but not properly recorded, causing rendering failures. diff --git a/packages/react/runtime/__test__/list.test.jsx b/packages/react/runtime/__test__/list.test.jsx index 0aa5ef5f38..68b3808388 100644 --- a/packages/react/runtime/__test__/list.test.jsx +++ b/packages/react/runtime/__test__/list.test.jsx @@ -4045,6 +4045,223 @@ describe('nested list', () => { `); }); + it('should record lazily created nested lists', () => { + const s1 = __SNAPSHOT__( + + s1 + {HOLE} + , + ); + const s2 = __SNAPSHOT__( + + s2 + {HOLE} + , + ); + const s3 = __SNAPSHOT__( + + s3 + , + ); + + const a = new SnapshotInstance(s); + + const b = new SnapshotInstance(s1); + a.insertBefore(b); + b.ensureElements(); + const parentListRef = b.__elements[3]; + + const c1 = new SnapshotInstance(s2); + const c2 = new SnapshotInstance(s2); + const c3 = new SnapshotInstance(s2); + + b.insertBefore(c1); + b.insertBefore(c2); + b.insertBefore(c3); + + const d1 = new SnapshotInstance(s3); + c1.insertBefore(d1); + + const d2 = new SnapshotInstance(s3); + c2.insertBefore(d2); + + const d3 = new SnapshotInstance(s3); + c3.insertBefore(d3); + __pendingListUpdates.flush(); + + expect(__pendingListUpdates.values).toMatchInlineSnapshot(` + { + "-6": [ + { + "insertAction": [ + { + "position": 0, + "type": "__Card__:__snapshot_a94a8_test_74", + }, + ], + "removeAction": [], + "updateAction": [], + }, + ], + "-7": [ + { + "insertAction": [ + { + "position": 0, + "type": "__Card__:__snapshot_a94a8_test_74", + }, + ], + "removeAction": [], + "updateAction": [], + }, + ], + "-8": [ + { + "insertAction": [ + { + "position": 0, + "type": "__Card__:__snapshot_a94a8_test_74", + }, + ], + "removeAction": [], + "updateAction": [], + }, + ], + } + `); + + elementTree.triggerComponentAtIndex(parentListRef, 0); + elementTree.triggerComponentAtIndex(parentListRef, 1); + // enqueue c1 + elementTree.triggerEnqueueComponent(parentListRef, 0); + // c3 reuse c1 + elementTree.triggerComponentAtIndex(parentListRef, 2); + // c1 re-create + elementTree.triggerComponentAtIndex(parentListRef, 0); + // should have 4 list-item now + expect(parentListRef).toMatchInlineSnapshot(` + + + + + + + + + + + + + + + + + + + + + + + + + + + `); + }); + it('should clear attached lists & should flush during ensureElements', () => { const s1 = __SNAPSHOT__( @@ -4146,7 +4363,7 @@ describe('update-list-info profile', () => { { "args": { "list id": "3", - "update list info": "{"insertAction":[{"position":0,"type":"__Card__:__snapshot_a94a8_test_76"},{"position":1,"type":"__Card__:__snapshot_a94a8_test_76"},{"position":2,"type":"__Card__:__snapshot_a94a8_test_76"}],"removeAction":[],"updateAction":[]}", + "update list info": "{"insertAction":[{"position":0,"type":"__Card__:__snapshot_a94a8_test_79"},{"position":1,"type":"__Card__:__snapshot_a94a8_test_79"},{"position":2,"type":"__Card__:__snapshot_a94a8_test_79"}],"removeAction":[],"updateAction":[]}", }, }, ], diff --git a/packages/react/runtime/src/snapshot.ts b/packages/react/runtime/src/snapshot.ts index 7a53cf7638..c571cc3bc4 100644 --- a/packages/react/runtime/src/snapshot.ts +++ b/packages/react/runtime/src/snapshot.ts @@ -335,6 +335,13 @@ export class SnapshotInstance { // In nested list scenarios, there are some `list` that are lazily created. // We need to `flush` them during `ensureElements`. // Also, `flush` is a safe operation since it checks if the `list` is in `__pendingListUpdates`. + if (__pendingListUpdates.values && !__pendingListUpdates.values[this.__id] && this.__firstChild !== null) { + let child: SnapshotInstance | null = this.__firstChild; + while (child) { + (__pendingListUpdates.values[this.__id] ??= new ListUpdateInfoRecording(this)).onInsertBefore(child); + child = child.__nextSibling; + } + } __pendingListUpdates.flushWithId(this.__id); } else { let index = 0;