All skills
vercel-labs avatar

/vercel-react-native-skills

@f2d73db
by Vercel Labsvercel-labs/openreview1.7k stars
118

React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.

Use this Skill: https://skilld.dev/gh/vercel-labs/openreview/vercel-react-native-skills

This session only. Nothing lands on disk.

ruleslist-performance-function-references.md

≈1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Optimize List Performance with Stable Object References

Don't map or filter data before passing to virtualized lists. Virtualization relies on object reference stability to know what changed—new references cause full re-renders of all visible items. Attempt to prevent frequent renders at the list-parent level.

Where needed, use context selectors within list items.

Incorrect (creates new object references on every keystroke):

function DomainSearch() {
  const { keyword, setKeyword } = useKeywordZustandState()
  const { data: tlds } = useTlds()

  // Bad: creates new objects on every render, reparenting the entire list on every keystroke
  const domains = tlds.map((tld) => ({
    domain: `${keyword}.${tld.name}`,
    tld: tld.name,
    price: tld.price,
  }))

  return (
    <>
      <TextInput value={keyword} onChangeText={setKeyword} />
      <LegendList
        data={domains}
        renderItem={({ item }) => <DomainItem item={item} keyword={keyword} />}
      />
    </>
  )
}

Correct (stable references, transform inside items):

const renderItem = ({ item }) => <DomainItem tld={item} />

function DomainSearch() {
  const { data: tlds } = useTlds()

  return (
    <LegendList
      // good: as long as the data is stable, LegendList will not re-render the entire list
      data={tlds}
      renderItem={renderItem}
    />
  )
}

function DomainItem({ tld }: { tld: Tld }) {
  // good: transform within items, and don't pass the dynamic data as a prop
  // good: use a selector function from zustand to receive a stable string back
  const domain = useKeywordZustandState((s) => s.keyword + '.' + tld.name)
  return <Text>{domain}</Text>
}

Updating parent array reference:

Creating a new array instance can be okay, as long as its inner object references are stable. For instance, if you sort a list of objects:

// good: creates a new array instance without mutating the inner objects
// good: parent array reference is unaffected by typing and updating "keyword"
const sortedTlds = tlds.toSorted((a, b) => a.name.localeCompare(b.name))

return <LegendList data={sortedTlds} renderItem={renderItem} />

Even though this creates a new array instance sortedTlds, the inner object references are stable.

With zustand for dynamic data (avoids parent re-renders):

const useSearchStore = create<{ keyword: string }>(() => ({ keyword: '' }))

function DomainSearch() {
  const { data: tlds } = useTlds()

  return (
    <>
      <SearchInput />
      <LegendList
        data={tlds}
        // if you aren't using React Compiler, wrap renderItem with useCallback
        renderItem={({ item }) => <DomainItem tld={item} />}
      />
    </>
  )
}

function DomainItem({ tld }: { tld: Tld }) {
  // Select only what you need—component only re-renders when keyword changes
  const keyword = useSearchStore((s) => s.keyword)
  const domain = `${keyword}.${tld.name}`
  return <Text>{domain}</Text>
}

Virtualization can now skip items that haven't changed when typing. Only visible items (~20) re-render on keystroke, rather than the parent.

Deriving state within list items based on parent data (avoids parent re-renders):

For components where the data is conditional based on the parent state, this pattern is even more important. For example, if you are checking if an item is favorited, toggling favorites only re-renders one component if the item itself is in charge of accessing the state rather than the parent:

function DomainItemFavoriteButton({ tld }: { tld: Tld }) {
  const isFavorited = useFavoritesStore((s) => s.favorites.has(tld.id))
  return <TldFavoriteButton isFavorited={isFavorited} />
}

Note: if you're using the React Compiler, you can read React Context values directly within list items. Although this is slightly slower than using a Zustand selector in most cases, the effect may be negligible.

Source: SKILL.md on GitHub

No alerts17d4 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    This skill provides a comprehensive set of React Native and Expo best practices optimized for AI agents and LLMs. It focuses on performance optimization, UI patterns, and proper state management within mobile applications. The skill is entirely composed of documentation and guidelines without any executable scripts or hidden network operations, making it safe for use.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer6mo

    39 files scanned · No issues

Signed by skilld at f2d73db. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Dormantupdated 7 months ago
metadata
{
  "author": "vercel",
  "version": "1.0.0"
}
  • Performance
  • react-native
  • expo
  • animations
  • reanimated
  • flashlist
  • mobile
  • native-modules
  • monorepo

README badge

README badge for vercel-labs/openreview/vercel-react-native-skills

Provides React Native and Expo best practices organized by priority, covering list performance, animations, navigation, UI patterns, and native module configuration. Use when building or optimizing React Native components, implementing Reanimated animations, or configuring native dependencies in Expo projects.

Generated from the current SKILL.md.

Does this skill cover both React Native and Expo?
Yes. The skill provides best practices for React Native and Expo applications, including Expo-specific patterns like expo-image and config plugins.
What animation library does this skill assume?
Reanimated. The skill includes rules for animating with Reanimated, such as using useDerivedValue and limiting animations to transform and opacity properties.
Does this skill address monorepo setups?
Yes. It includes rules for structuring monorepo projects with native dependencies, such as keeping native dependencies in the app package and maintaining single dependency versions across packages.
What is the priority focus of this skill?
List performance is marked as critical priority, covering virtualization with FlashList, memoization, and image optimization. Animation and navigation are high priority.

Generated from the current SKILL.md. These answers refresh after source changes.