All skills
callstackincubator avatar

/react-native-best-practices

@fa0bad0 official

Provides React Native performance optimization guidelines for FPS, TTI, bundle size, memory leaks, re-renders, and animations. Applies to tasks involving Hermes optimization, JS thread blocking, bridge overhead, FlashList, native modules, or debugging jank and frame drops.

Use this Skill: https://skilld.dev/gh/callstackincubator/agent-skills/react-native-best-practices

This session only. Nothing lands on disk.

referencesnative-view-flattening.md

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

Skill: View Flattening

Understand and debug React Native's view flattening optimization.

Quick Pattern

Problem (children get flattened unexpectedly):

<NativeTabBar>
  <Tab1 />  // May be flattened, breaking native component
  <Tab2 />
</NativeTabBar>

Solution (prevent flattening):

<NativeTabBar>
  <Tab1 collapsable={false} />
  <Tab2 collapsable={false} />
</NativeTabBar>

When to Use

  • Native component receives unexpected number of children
  • Layout debugging with native components
  • Building native components that accept children
  • Understanding React Native rendering

Note: This skill involves visual view hierarchy tools (Xcode Debug View Hierarchy, Android Layout Inspector). Use agent-device for screen evidence; install it through the environment's approved/trusted path or ask the user if verification needs it and it is missing. Native hierarchy inspection may still require Xcode, Android Studio, or human review. Record native child counts and component names in text when asking an agent to reason about them.

What is View Flattening?

React Native's renderer automatically removes "layout-only" views that:

  • Only affect layout (no visual rendering)
  • Don't need to exist in native view hierarchy

Benefits: Reduced memory, faster rendering, shallower view tree.

The Problem with Native Components

// You expect 3 children
<MyNativeComponent>
  <Child1 />
  <Child2 />
  <Child3 />
</MyNativeComponent>

If a child wrapper is flattened, native code may receive a different child count or shape than the JS tree suggests.

Preventing Flattening with collapsable

<MyNativeComponent>
  <Child1 collapsable={false} />
  <Child2 collapsable={false} />
  <Child3 collapsable={false} />
</MyNativeComponent>

The direct views marked collapsable={false} are preserved as native children.

Debugging View Hierarchy

View Hierarchy Flattening

Use native debugging tools to see the actual view hierarchy:

Xcode (iOS)

  1. Run app via Xcode
  2. Click "Debug View Hierarchy" in debug toolbar (shown in image)
  3. Inspect 3D view of native hierarchy

Component class names vary by architecture and React Native version; verify the actual native hierarchy in the tool.

Android Studio

  1. Run app via Android Studio
  2. View → Tool Windows → Layout Inspector
  3. Select running process

Component class names vary by architecture and React Native version; verify the actual native hierarchy in the tool.

Code Examples

When Flattening Breaks Your Component

// Your native component expects exactly 2 tabs
const NativeTabBar = requireNativeComponent('RCTTabBar');

// BAD: TabContent might get flattened
const MyTabs = () => (
  <NativeTabBar>
    <TabContent title="Home">
      <View><Text>Home content</Text></View>
    </TabContent>
    <TabContent title="Profile">
      <View><Text>Profile content</Text></View>
    </TabContent>
  </NativeTabBar>
);

// GOOD: Prevent flattening
const MyTabs = () => (
  <NativeTabBar>
    <TabContent title="Home" collapsable={false}>
      <View><Text>Home content</Text></View>
    </TabContent>
    <TabContent title="Profile" collapsable={false}>
      <View><Text>Profile content</Text></View>
    </TabContent>
  </NativeTabBar>
);

Wrapper Component with collapsable

// Wrapper that prevents flattening
const NativeChildWrapper = ({ children, ...props }) => (
  <View collapsable={false} {...props}>
    {children}
  </View>
);

// Usage
<NativeComponent>
  <NativeChildWrapper>
    <ComplexChild />
  </NativeChildWrapper>
</NativeComponent>

When Views Get Flattened

React Native can flatten layout-only wrappers that do not need their own native view for drawing, events, accessibility, measurement, or native-component child semantics. The exact rules vary across renderer versions.

Forcing a View to Stay

Use collapsable={false} as the stable fix. Style or handler changes can be useful as debugging probes, but do not keep them as the production solution:

// Diagnostic probes only
<View style={{ backgroundColor: 'transparent' }} />
<View style={{ borderWidth: 0.01 }} />
<View style={{ opacity: 0.99 }} />
<View onLayout={() => {}} />

Remove these probes after confirming flattening is the issue.

Debugging Checklist

  1. Check native child count: Log received children in native code
  2. Use Layout Inspector: Visual hierarchy debugging
  3. Add collapsable={false}: Test if flattening is the issue
  4. Check wrapper components: Intermediate views may be flattened

Common Pitfalls

  • Assuming JS children = native children: Flattening changes this
  • Not documenting native component requirements: If your native component expects specific child count, document it
  • Over-using collapsable={false}: Only use when necessary (loses optimization benefits)

Related Skills

Source: SKILL.md on GitHub

1 alert17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    This skill provides a comprehensive performance optimization guide for React Native applications. It contains standard developer workflows using command-line tools and patterns for advanced techniques like remote code splitting, which include detailed security hardening advice.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer7mo

    11/31 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

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

Last checked against GitHub 2 weeks ago.

Activeupdated 2 months ago
  • Performance
  • react-native
  • optimization
  • profiling
  • fps
  • bundle-size
  • memory
  • hermes
  • flatlist
  • animations

README badge

README badge for callstackincubator/agent-skills/react-native-best-practices

Provides React Native performance optimization guidelines covering FPS, TTI, bundle size, memory leaks, re-renders, and animations. Includes reference documentation for Hermes, FlashList, Turbo Modules, React Compiler, Reanimated, and profiling with Xcode and Android Studio.

Generated from the current SKILL.md.

Does this skill cover Expo apps?
Yes. The guidelines apply to both bare React Native and Expo projects. Expo SDK 52+ supports tree shaking and Re.Pack code splitting.
What performance metrics should I measure first?
Start with FPS (use React Native DevTools), Time To Interactive (TTI), bundle size, and memory growth. The skill emphasizes measuring baseline metrics before and after optimization to validate improvements.
Does this cover Hermes optimization?
Yes. The skill includes Hermes-specific guidance such as disabling JS bundle compression on Android to enable mmap, and checking Hermes API coverage before removing polyfills.
What if I'm using a list library other than FlatList or FlashList?
The skill prioritizes FlatList and FlashList as virtualized replacements for ScrollView. It includes library version checks (e.g., FlashList v2 API changes) but focuses on these two libraries.
Does this include native profiling guidance?
Yes. The skill covers profiling with Xcode Instruments (iOS) and Android Studio CPU Profiler, plus guidance on native threading, Turbo Modules, and C++ performance-critical code.

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