Skip to content
Development
Agent

list-performance

<!-- Loaded by react-native-engineer when task involves lists, FlatList, FlashList, LegendList, virtualization, renderItem, scroll performance -->

From plugin
vexjoy-agent
449198 skills198 agents12 commands83 hooks

Claude Code

$ npx -y skills add notque/vexjoy-agent --agent claude-code

Agent definition

list-performance.md

List Performance Reference

<!-- Loaded by react-native-engineer when task involves lists, FlatList, FlashList, LegendList, virtualization, renderItem, scroll performance -->

Use a Virtualizer for Any Scrollable List

**Impact:** CRITICAL — only visible items rendered, reduces memory and mount time

**Instead of:**

<ScrollView>
  {items.map((item) => <ItemCard key={item.id} item={item} />)}
</ScrollView>

**Use:**

import { LegendList } from '@legendapp/list'

function Feed({ items }: { items: Item[] }) {
  return (
    <LegendList
      data={items}
      renderItem={({ item }) => <ItemCard item={item} />}
      keyExtractor={(item) => item.id}
      estimatedItemSize={80}
    />
  )
}

---

Keep Stable Object References — Transform Inside Items

**Impact:** CRITICAL — virtualization skips re-renders only when references are stable

Mapping/filtering before passing to list creates new references every render, forcing full re-renders on every state update.

**Instead of:**

const domains = tlds.map((tld) => ({
  domain: `${keyword}.${tld.name}`,
  price: tld.price,
}))
return <LegendList data={domains} ... />

**Use:**

<LegendList
  data={tlds}  // stable references
  renderItem={({ item }) => <DomainItem tld={item} />}
/>

function DomainItem({ tld }: { tld: Tld }) {
  const domain = useKeywordStore((s) => s.keyword + '.' + tld.name)
  return <Text>{domain}</Text>
}

New sorted arrays are fine if inner object references stay the same: `tlds.toSorted(...)`.

---

Pass Primitives and Stable References to List Items

**Impact:** HIGH — prevents re-renders of memoized items

Inline objects/styles in `renderItem` create new references every render, breaking `memo()`.

**Instead of:**

renderItem={({ item }) => (
  <UserRow
    user={{ id: item.id, name: item.name }}
    style={{ backgroundColor: item.isActive ? 'green' : 'gray' }}
  />
)}

**Use:**

renderItem={({ item }) => (
  <UserRow id={item.id} name={item.name} isActive={item.isActive} />
)}

// Or hoist static styles to module scope
const activeStyle = { backgroundColor: 'green' }
const inactiveStyle = { backgroundColor: 'gray' }

---

Pass Primitives for Effective Memoization

**Impact:** HIGH — enables shallow comparison in memo()

**Instead of:**

const UserRow = memo(function UserRow({ user }: { user: User }) {
  return <Text>{user.name}</Text>
})
renderItem={({ item }) => <UserRow user={item} />}

**Use:**

const UserRow = memo(function UserRow({ id, name }: { id: string; name: string }) {
  return <Text>{name}</Text>
})
renderItem={({ item }) => <UserRow id={item.id} name={item.name} />}

---

Hoist Callbacks to the Root — Items Call with ID

**Impact:** HIGH — single stable callback vs new closure per item

**Instead of:**

renderItem={({ item }) => {
  const onPress = () => handlePress(item.id)
  return <Item item={item} onPress={onPress} />
}}

**Use:**

const onPress = useCallback((id: string) => handlePress(id), [handlePress])
renderItem={({ item }) => <Item item={item} onPress={onPress} />}

---

Keep List Items Lightweight

**Impact:** HIGH — reduces per-item render time during scroll

**Instead of:**

function ProductRow({ id }: { id: string }) {
  const { data: product } = useQuery(['product', id], () => fetchProduct(id))
  const theme = useContext(ThemeContext)
  const cart = useContext(CartContext)
  const recs = useMemo(() => computeRecommendations(product), [product])
  return <View>{/* ... */}</View>
}

**Use:**

function ProductList() {
  const { data: products } = useQuery(['products'], fetchProducts)
  return (
    <LegendList
      data={products}
      renderItem={({ item }) => (
        <ProductRow name={item.name} price={item.price} imageUrl={item.image} />
      )}
    />
  )
}

function ProductRow({ name, price, imageUrl }: Props) {
  const inCart = useCartStore((s) => s.items.has(id))
  return <View>{/* ... */}</View>
}

No queries in items, no expensive computations, prefer Zustand selectors over Context.

---

Use Item Types for Heterogeneous Lists

**Impact:** HIGH — efficient recycling, prevents layout thrashing

<LegendList
  data={items}
  keyExtractor={(item) => item.id}
  getItemType={(item) => item.type}
  getEstimatedItemSize={(index, item, itemType) => {
    switch (itemType) {
      case 'header': return 48
      case 'message': return 72
      case 'image': return 300
      default: return 72
    }
  }}
  renderItem={({ item }) => {
    switch (item.type) {
      case 'header': return <SectionHeader title={item.title} />
      case 'message': return <MessageRow text={item.text} />
      case 'image': return <ImageRow url={item.url} />
    }
  }}
  recycleItems
/>

---

Use Compressed, Appropriately-Sized Images in Lists

**Impact:** HIGH — reduces memory; thumbnails load at display dimensions

**Instead of:**

<Image source={{ uri: product.imageUrl }} style={{ width: 100, height: 100 }} />

**Use:**

import { Image } from 'expo-image'

function ProductItem({ product }: { product: Product }) {
  const thumbnailUrl = `${product.imageUrl}?w=200&h=200&fit=cover`  // 2x retina

  return (
    <Image
      source={{ uri: thumbnailUrl }}
      style={{ width: 100, height: 100 }}
      contentFit="cover"
      recyclingKey={product.id}
    />
  )
}

Use `expo-image` for list images — memory-efficient caching and `recyclingKey` for recycled cells.

Read more
@notque
Ships withvexjoy-agent

Essays and writing behind this toolkit live at vexjoy.com. VexJoy Agent connects plain-English requests to specialist agents, skills, and workflows. /do selects the knowledge and tools needed for your task.

44964 skills198 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
449
Star history of notque/vexjoy-agent on GitHub, a chart by star-history.com

Other agents on vexjoy-agent.

modules

modules

Agent

**Scope**: Module selection patterns, builtin vs command/shell decisions, collection modules, and version-specific module changes…

@notque@notqueInstall Agent
testing

testing

Agent

**Scope**: Molecule test scenarios, ansible-lint rules, idempotency validation, and check-mode patterns **Version range**:…

@notque@notqueInstall Agent
communication-patterns

communication-patterns

Agent

**Scope**: Failure modes in agent output style — over-reporting, self-congratulation, verbose narration, and hedging. Covers what…

@notque@notqueInstall Agent

More agents from other plugins.

a11y-architect
Auto-invoked

a11y-architect

Agent

Accessibility Architect specializing in WCAG 2.2 compliance for Web and Native platforms. Use PROACTIVELY when designing UI…

ecc13d293k
@affaan-m@affaan-mInstall Agent
analyze-pass-impact

analyze-pass-impact

Agent

Analyzes how a specific topic affects a group of compiler passes. Used by the /plan-update skill to parallelize research across…

react2d252k
@facebook@facebookInstall Agent
orchestrator

orchestrator

Agent

- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as…

codex2d135k
@openai@openaiInstall Agent
cavecrew-builder

cavecrew-builder

Agent

Surgical 1-2 file edit. Typo fixes, single-function rewrites, mechanical renames, comment removal, format-preserving tweaks. Hard…

caveman3d119k
@juliusbrussee@juliusbrusseeInstall Agent

Questions about list-performance.

Which coding agents can use list-performance?
list-performance installs in Claude Code and Cursor: each loads subagents from .claude/agents, so copy the file there. Flowy's auto-invocation runs in Claude Code only.