Skip to content

fix: recycling hooks crash when rendered outside of a LegendList - #498

Merged
jmeistrich merged 1 commit into
LegendApp:mainfrom
Daniel-Griffiths:fix/recycling-hooks-outside-list
Aug 8, 2026
Merged

fix: recycling hooks crash when rendered outside of a LegendList#498
jmeistrich merged 1 commit into
LegendApp:mainfrom
Daniel-Griffiths:fix/recycling-hooks-outside-list

Conversation

@Daniel-Griffiths

@Daniel-Griffiths Daniel-Griffiths commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

The bug

Since 3.3.2, calling useRecyclingEffect or useRecyclingState in a component that is rendered outside of a LegendList throws:

TypeError: Cannot read property 'values' of null

This was a regression in 3.3.2's recycling-hooks rework ("Recycled rows update their current item without changing the container context"): the hooks now read the current item through useArr$createSelectorFunctionsArr, which dereferences ctx.values in peek$ without checking that the ContextState provider exists. In 3.3.0 the hooks only touched the container context, which is null-safe, so shared item components (e.g. a swipeable row used both inside a list and in a plain ScrollView or modal) worked fine.

Other hooks in ContextContainer.ts already treat this as a supported case ("Fail gracefully if used outside context"), so this restores that behavior for the signal-reading path.

The fix

createSelectorFunctionsArr returns a no-op selector (stable empty array, no-op subscribe) when there is no state context, and useArr$ / useSelector$ drop their non-null assertions so the null flows through with correct types. useContainerItemInfo already returns undefined when there's no container context, so the hooks no-op exactly as they did in 3.3.0.

Tests

Added __tests__/hooks/useRecyclingEffect.test.tsx covering both hooks rendered outside a list — both fail with the TypeError before the fix and pass after. Full suite: 1468 pass, 1 pre-existing failure (LegendList.bootstrapInitialScroll.oldarch.test.ts, fails identically on clean main in my environment). biome check clean.


For the meantime this is the patch I am using to resolve this issue in my apps using 3.3.2

diff --git a/node_modules/@legendapp/list/react-native.js b/node_modules/@legendapp/list/react-native.js
index 338c18f..d1cd341 100644
--- a/node_modules/@legendapp/list/react-native.js
+++ b/node_modules/@legendapp/list/react-native.js
@@ -178,6 +178,14 @@ function useStateContext() {
   return React2__namespace.useContext(ContextState);
 }
 function createSelectorFunctionsArr(ctx, signalNames) {
+  if (!ctx) {
+    const emptyValues = [];
+    return {
+      get: () => emptyValues,
+      subscribe: () => () => {
+      }
+    };
+  }
   let lastValues = [];
   let lastSignalValues = [];
   return {
diff --git a/node_modules/@legendapp/list/react-native.mjs b/node_modules/@legendapp/list/react-native.mjs
index 32c194f..1c6f1d5 100644
--- a/node_modules/@legendapp/list/react-native.mjs
+++ b/node_modules/@legendapp/list/react-native.mjs
@@ -157,6 +157,14 @@ function useStateContext() {
   return React2.useContext(ContextState);
 }
 function createSelectorFunctionsArr(ctx, signalNames) {
+  if (!ctx) {
+    const emptyValues = [];
+    return {
+      get: () => emptyValues,
+      subscribe: () => () => {
+      }
+    };
+  }
   let lastValues = [];
   let lastSignalValues = [];
   return {

@Daniel-Griffiths
Daniel-Griffiths force-pushed the fix/recycling-hooks-outside-list branch from f2148e2 to 7fa34f8 Compare July 14, 2026 19:53
@jmeistrich
jmeistrich force-pushed the fix/recycling-hooks-outside-list branch from 7fa34f8 to 333ce86 Compare August 8, 2026 00:19
@jmeistrich
jmeistrich merged commit 0cab22b into LegendApp:main Aug 8, 2026
@jmeistrich

Copy link
Copy Markdown
Member

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants