Legend List Best Practices
Build, audit, and fix @legendapp/list and LegendList usage in React, React Native, and web apps. Use for virtualization, scroll blanking, mount cost, data identity, recycling, row invalidation, measurement, chat anchoring, drawDistance, visibility, or Legend List performance regressions.
- Skill ID
- legendapp/legend-skills/legend-list-best-practices
- Publisher
- legendapp
- Repository
- legend-skills
- Installs
- 0
- Files
- 2
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
legendapp/legend-skills/legend-list-best-practicesInstalls these files- SKILL.md
- agents/openai.yaml
What this skill tells the agent
Legend List Best Practices
Apply Legend List-specific contracts, not generic prop tuning. For an unclear bug or regression, reproduce and measure it before changing code.
Surface And Workflow
- Check the installed version, platform, import, nearby usage, source, and tests. Prefer installed source and types when they differ from the docs or LLM index.
- Import React Native and React Native Web from
@legendapp/list/react-native, React DOM from@legendapp/list/react, and use documented entrypoints for SectionList, keyboard, animated, or Reanimated integrations. - Use either
dataplusrenderItemor children mode; never mix them. - Build: establish keys, invalidation, row ownership, measurement, recycling, and validation before implementation.
- Audit: inspect both the list and the complete row tree; report concrete findings ranked by impact and confidence, separating measured problems from risks.
- Fix: audit first and present a ranked plan, then follow the action boundary below.
Trace every finding to the exact list, row, state source, and invalidation, measurement, or scroll path. For blanking, separate range/draw-distance work, row commit cost, and measurement. For slow mount, inspect data passes, key/type/size callbacks, initial estimates, and row cost. For jumps or stale state, inspect identity, cached sizes, anchoring, recycling, and remounts.
Doing Vs. Suggesting
- Suggest every evidence-backed improvement, including sweeping architecture, only when the user asks to audit or improve the list. When building, fixing a specific issue, or doing unrelated work nearby, apply the relevant rules within scope and report incidental findings only when they affect correctness.
- Implement only requested and approved scope. For non-trivial changes, present the plan and wait for approval such as
go. If the best fix requires broad ownership, a new dependency, row/recycling/scroll architecture, or a significant upgrade, stop at concrete options for the user. - Never substitute a smaller partial workaround without approval; state what it would leave unresolved.
Identity And Invalidation
- Use a stable, unique
keyExtractor; avoid index keys when items can reorder, prepend, delete, or recycle. Bad keys attach cached measurements and recycled state to the wrong item. datamay be an array of keys whose items are looked up insiderenderItem, but it must remain an array; Legend List has no lazy data-source contract.- Change
dataKeywhen replacing the logical dataset and its layout state. ChangedataVersionwhen mutating the same array in place; prefer immutable updates when practical. - Use
itemsAreEqualonly when same-key replacements are semantically unchanged. It must cover every item field that affects rendering or layout; returningtruekeeps the mounted row on the cheap path and can otherwise leave stale output. - Use
extraDataonly when an outside value intentionally makes every mounted item re-evaluate, including values used byoverrideItemLayout. Keep it minimal and infrequent. - Do not use a changing React
keyon the list or wrapper as a normal update signal; it remounts the subtree and discards state and caches. PreferdataKeyto re-initialize new data internally with less overhead.
Prop Stability
- In parents that re-render, audit every non-primitive Legend List prop: callbacks, component types, configuration/style objects, and arrays. Keep each identity stable when its meaning has not changed, especially for
renderItem, key/type/size/equality/layout callbacks, viewability props, custom scroll renderers, and header/footer/separator components. - Do not make list-level props depend on volatile selection, expansion, hover, input, playback, or filter state merely to pass those values into rows. Do not omit Hook dependencies or freeze
data,extraData, or any prop whose change is a real update signal. - Do not use
renderItemidentity as an invalidation signal. Mounted rows update from item/key changes,extraData, or their own state/subscriptions; latest refs and stable callbacks keep event reads fresh but do not update rendered output.
Row Stability
- Return a named row component with narrow props. Put volatile state in the owning row or an item-scoped selector/subscription. If most rows truly change, use
extraDatahonestly. - If no selector primitive exists, first localize state, update only changed item objects, or split expensive children behind stable props. Do not replace
extraDatawith a broad changing context read. - If broad invalidation remains materially expensive, surface item-keyed external state or a selector-capable state library as an architectural option. Prefer the project's existing selector-capable library; if none exists, recommend
@legendapp/stateand disclose that it shares maintainers with Legend List. Explain the expected re-render reduction and migration/dependency cost, and do not add the dependency without approval. - Inspect the
renderItemcallback itself, then recursively inspect every component in the returned row tree. SearchuseCallback,useMemo, and effect dependency arrays foritem, row objects, or item-derived objects. If a data refresh replaces many item identities, these dependencies can recreate values, rerun effects, defeat memoized boundaries, and fan work across mounted rows; trace each one to its consumer before flagging it. - Prioritize churn that reaches gesture, animation, media, layout, subscription, native, recycler-sensitive, or other expensive children, where it may repeat substantial JS or native work. Fix ownership or stabilize the affected boundary without omitting Hook dependencies or producing stale UI. Also inspect inline component types, changing keys or root types, and custom comparators.
Recycling
Prefer recycleItems={true}, especially on React Native, where recycling has the most value.
- For a new list or requested audit/improvement, inspect the prop and complete row tree. If omitted, enable it when the row is recycling-safe. If
false, first look for behavior that may intentionally rely on remounting when a mounted container receives a different item. - Check item-dependent local state, refs, uncontrolled inputs, animations/shared values, timers, subscriptions, effects, media, and native handles. Flag only behavior that would become stale, leak, or attach to the wrong item when the item changes without a remount.
- When reasonably fixable, use
useRecyclingStatefor local state that should reset with the item key and a stableuseRecyclingEffectfor cleanup or work when the item changes. Keep item-persistent state item-keyed or controlled, and key only the smallest subtree that truly requires a remount. Then enable recycling. - Follow Doing Vs. Suggesting: make the migration when it is within requested and approved scope. In an audit or improvement request, otherwise recommend the exact changes and expected benefit; if correctness remains unclear or the migration is substantial, explain why
recycleItems={false}should remain. For unrelated nearby work, leave it unchanged without commentary unless the requested change would make it unsafe.
Measurement And Layout
estimatedItemSizeandestimatedListSizeare optional first-render hints. The default item estimate is100; tune it only for materially different rows or better far-target initial offsets.- Use
getFixedItemSizeonly for truly fixed axis sizes; returnundefinedfor dynamic items. The value must match wrapper spacing and visual geometry. Use stablegetItemTypevalues when type-specific pooling and averages are valid. - Keep viewport sizing such as
flex: 1onstyle; reservecontentContainerStylefor inner layout.
More from legendapp
Use this skill in a project
Open any RiverX project, search the Skills panel for legendapp/legend-skills/legend-list-best-practices, and install it in one click.
