Skip to content

Nested SafeAreaProvider ignores parent's initialMetrics, causes flash on mount #689

@marcospgp

Description

@marcospgp

Update: Root cause identified

After extensive debugging, we found the root cause is not the nested SafeAreaProvider itself, but
how it interacts with NativeTabs pre-rendering.

The actual problem

  1. NativeTabs (expo-router) pre-renders ALL tabs simultaneously when the app loads
  2. At pre-render time, nested SafeAreaProviders haven't measured yet
  3. Components get the root provider's value (device safe area only, e.g. 34px)
  4. When user visits a tab, the nested SafeAreaProvider measures bounded insets (e.g. 83px including tab
    bar)
  5. This causes a visible jump as the layout shifts

What we tried

  • Context-based caching: Doesn't work because NativeTabs isolates React context between tabs
  • Module-level caching: Doesn't help the first tab because all tabs pre-render simultaneously before
    any measurement
  • SafeAreaView: Uses the existing provider's values, doesn't measure bounded insets
  • initialMetrics: We don't know the bounded value ahead of time

The fundamental issue

There's no way to get synchronous bounded insets from a nested SafeAreaProvider. The measurement is
always async, but NativeTabs pre-renders tabs before measurement completes.

Current workaround

Accept the flash as a known limitation. It only occurs on first visit to each tab (components stay
mounted after).

Potential library-level fixes

  1. Option to pass a callback/promise to initialMetrics that resolves after first measurement
  2. A useSafeAreaInsetsSync() hook that blocks render until measurement completes
  3. Better documentation about this interaction with tab navigators that pre-render

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions