diff --git a/.changeset/plenty-kiwis-live.md b/.changeset/plenty-kiwis-live.md
new file mode 100644
index 0000000000..d9842e15d7
--- /dev/null
+++ b/.changeset/plenty-kiwis-live.md
@@ -0,0 +1,5 @@
+---
+"@lynx-js/react": patch
+---
+
+Should only recycle off-screen `list-item` in recursive hydration.
diff --git a/packages/react/runtime/__test__/list.test.jsx b/packages/react/runtime/__test__/list.test.jsx
index ac8d0bc6fb..8496f884e4 100644
--- a/packages/react/runtime/__test__/list.test.jsx
+++ b/packages/react/runtime/__test__/list.test.jsx
@@ -1774,6 +1774,11 @@ describe('list reload', () => {
hydrate(b, bb);
b.unRenderElements();
+ // Should only update `list-item` in the recycling pool
+ // Should not add the on-screen `list-item` to the recycling pool,
+ expect([...recycleSignMap.keys()]).toStrictEqual([__GetElementUniqueID(d3.__element_root)]);
+ expect(recycleSignMap.get(__GetElementUniqueID(d3.__element_root))).not.toBe(d3);
+
// The one rendered should be removed
expect(root).toMatchInlineSnapshot(`
@@ -1940,7 +1945,11 @@ describe('list reload', () => {
expect(signMap.get(__GetElementUniqueID(d1.__element_root))).toBe(d2_); // note: d1 is reused by d2_
expect(signMap.get(__GetElementUniqueID(d2_.__element_root))).toBe(d2_);
expect(signMap.get(__GetElementUniqueID(d3_.__element_root))).toBe(d3_);
- expect(recycleSignMap.get(__GetElementUniqueID(d3_.__element_root))).toBe(d3_);
+ // d1 was enqueued as well, so it should be in the recycling pool
+ expect([...recycleSignMap.keys()]).toStrictEqual([
+ __GetElementUniqueID(d3.__element_root),
+ __GetElementUniqueID(d1.__element_root),
+ ]);
});
});
diff --git a/packages/react/runtime/src/hydrate.ts b/packages/react/runtime/src/hydrate.ts
index d161a16b31..bbdca7453b 100644
--- a/packages/react/runtime/src/hydrate.ts
+++ b/packages/react/runtime/src/hydrate.ts
@@ -332,7 +332,12 @@ export function hydrate(before: SnapshotInstance, after: SnapshotInstance, optio
}
if (recycleMap.has(a.type)) {
const recycleSignMap = recycleMap.get(a.type)!;
- recycleSignMap.set(listItemID, b);
+ // Should only update `list-item` in the recycling pool
+ // Because if an on-screen `list-item` is added to the recycling pool,
+ // it could cause a blank screen when reused next time, as it may still be visible.
+ if (recycleSignMap.has(listItemID)) {
+ recycleSignMap.set(listItemID, b);
+ }
}
}
},