All skills

Complete React Native and Expo optimization guide combining Callstack profiling with Vercel code patterns. Covers FPS, TTI, bundle size, memory, lists, animations, state, UI, and React Compiler. Use for any React Native performance, debugging, or best practices task.

Use this Skill: https://skilld.dev/gh/gigs-slc/react-native-skills/react-native

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 interpreting visual view hierarchy tools (Xcode Debug View Hierarchy, Android Layout Inspector). AI agents cannot yet process screenshots autonomously. Use this as a guide while reviewing the hierarchy manually, or await MCP-based visual feedback integration (see roadmap).

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 Child1 is flattened, its internal views become direct children:

// Native side receives 5 views instead of 3!
<MyNativeComponent>
  <View />   // Was inside Child1
  <View />   // Was inside Child1  
  <View />   // Was inside Child1
  <Child2 />
  <Child3 />
</MyNativeComponent>

Preventing Flattening with collapsable

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

Now native side always receives exactly 3 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

React Native components map to:

  • <View /> → RCTViewComponentView
  • <Text /> → RCTTextView

Android Studio

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

React Native components map to:

  • <View /> → ReactViewGroup
  • <Text /> → ReactTextView

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

Views are considered "layout-only" when they:

  • Have no backgroundColor
  • Have no borderWidth, borderColor
  • Have no shadowColor, elevation
  • Don't handle events (no onPress, etc.)
  • Don't use opacity < 1
  • Don't have overflow: 'hidden'

Forcing a View to Stay

Besides collapsable={false}, these also prevent flattening:

// Any of these prevent flattening
<View style={{ backgroundColor: 'transparent' }} />
<View style={{ borderWidth: 0.01 }} />
<View style={{ opacity: 0.99 }} />
<View onLayout={() => {}} />

But collapsable={false} is the cleanest solution.

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

2 alerts6mo4 checks · Risk HIGH
  • Gen Agent Trust Hub7mo

    The skill is a technical React Native guide that includes a high-risk remote code execution pattern for installing a performance tool.

  • Socket6mo

    No alerts

  • Snyk7mo

    Risk: MEDIUM · No issues

  • Runlayer7mo

    7/67 files flagged

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

Last checked against GitHub 2 days ago.

Dormantupdated 8 months ago
Other metadata
metadata
{
  "author": "Callstack + Vercel",
  "version": "1.0.0",
  "tags": "react-native, expo, performance, optimization, patterns"
}

README badge

README badge for gigs-slc/react-native-skills/react-native