Skip to content

popToNative closes all React Native screens #354

Description

@iAndrew25

Hello,

I've been using react-native-brownfield for a while now and recently we added a new module inside the RNApp project.
A module is a separate stack which comes with its own screens and logic. Normally these modules should be as isolated as possible one from another.
The way I implemented the module is by using the NavigationContainer and the Stack.Navigator from react-navigation.

For testing purposes I've made a new SwiftUI view that allows me to navigate to each module based on the initialModule prop, and from React Native I am passing the prop to NavigationContainer's initialRouteName prop.

Now, just like in the attached video, if I navigate on Home module, then on Settings [native screen], then on Contact [RN screen], and then press the back button [which calls popToNative], it will close all the screens. Basically popToNative closes all the React Native screens.

I am not sure if this is the expected behavior or if it's a bug. I would expect popToNative to close only the React Native screens that are on the top of the stack.

Here is the code I am using:

import Brownie
import ReactBrownfield
import SwiftUI
import UIKit

enum HomeDestination: Hashable {
    case rnHome
    case nativeSettings
    case rnContact
}

@available(iOS 16.0, *)
struct ContentView: View {
    @State private var path = NavigationPath()

    var body: some View {
        ZStack(alignment: .topTrailing) {
            NavigationStack(path: $path) {
                Color(UIColor.systemBackground)
                    .ignoresSafeArea()
                    .navigationBarHidden(true)
                    .navigationDestination(for: HomeDestination.self) { dest in
                        destinationView(for: dest)
                    }
            }

            FloatingHomeButtons { destination in
                path.append(destination)
            }
            .padding(16)
        }
    }

    @ViewBuilder
    private func destinationView(for dest: HomeDestination) -> some View {
        switch dest {
        case .rnHome:
            RNScreen(initialModule: "Home")
        case .nativeSettings:
            SettingsScreen()
        case .rnContact:
            RNScreen(initialModule: "Contact")
        }
    }
}

private struct FloatingHomeButtons: View {
    let onSelect: (HomeDestination) -> Void

    var body: some View {
        VStack(alignment: .trailing, spacing: 12) {
            Button("Open RN-Home") { onSelect(.rnHome) }
                .buttonStyle(.borderedProminent)

            Button("Open Native-Settings") { onSelect(.nativeSettings) }
                .buttonStyle(.borderedProminent)

            Button("Open RN-Contact") { onSelect(.rnContact) }
                .buttonStyle(.borderedProminent)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topTrailing)
        .allowsHitTesting(true)
    }
}

struct RNScreen: View {
    let initialModule: String

    var body: some View {
        ReactNativeView(
            moduleName: "RNApp",
            initialProperties: [
                "nativeOsVersionLabel":
                    "\(UIDevice.current.systemName) \(UIDevice.current.systemVersion)",
                "initialModule": initialModule
            ]
        )
        .ignoresSafeArea()
        .navigationBarHidden(true)
    }
}

@available(iOS 16.0, *)
#Preview {
    ContentView()
}
export default function App({
  nativeOsVersionLabel,
  initialModule = 'Home',
}: AppProps) {
  const initialRouteName: InitialModule =
    initialModule === 'Contact' ? 'Contact' : 'Home';

  return (
    <NativeOsVersionLabelContext.Provider value={nativeOsVersionLabel}>
      <NavigationContainer>
        <Stack.Navigator
          initialRouteName={initialRouteName}
          screenOptions={{ headerShown: false }}
        >
          <Stack.Screen name="Home" component={HomeScreen} />
          <Stack.Screen name="Contact" component={ContactScreen} />
        </Stack.Navigator>
      </NavigationContainer>
    </NativeOsVersionLabelContext.Provider>
  );
}

Reproducible Demo

Simulator.Screen.Recording.-.iPhone.17.Pro.-.2026-05-26.at.22.58.58.mov

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