Skip to main content

From react-native-navigation

Move an app from react-native-navigation to @apexnative/navigation: the same native model, the new JavaScript API and setup, each old call mapped to the new one, and the move step by step.

This page moves an app from react-native-navigation to @apexnative/navigation. Both libraries share the model: native containers, options as data, the state owned by the platform. What changes is the JavaScript API and the setup. At the end the app has the same screens, layouts and options, and no react-native-navigation package.

This page answers:

  1. What the move needs first.
  2. What stays the same, and what changes in the app.
  3. Which API takes the place of which.
  4. The move, step by step, with each piece before and after.
  5. Which option keys kept their path, and which changed.
  6. What has no direct equivalent, and what to do instead.

Before you start​

react-native-navigation@apexnative/navigation
React Native0.77 or newer, the New Architecture0.85 or newer, the New Architecture only
iOSRNNAppDelegateANNAppDelegate, iOS 15.1 or newer
AndroidNavigationActivity, NavigationApplication of com.reactnativenavigationThe same class names, of dev.apexnative.navigation; minSdk 24
Packagereact-native-navigation, pod ReactNativeNavigation@apexnative/navigation, pod ApexNavigation

So the app first moves to React Native 0.85 or newer, if it isn't there yet. More: Requirements.

The two libraries can't share the app: each one takes the window and the startup. So the move happens in one branch, and the app runs again once no file imports react-native-navigation. The steps go in an order where TypeScript points at what is left.

The same model​

Both libraries work the same way underneath. The stacks, tabs, modals and side menus are the platform's own containers; each screen is a React component the platform shows in its own native screen; options are data the native side reads before the screen shows. Many option paths stay as they were: topBar.title.text, topBar.rightButtons, bottomTabs.visible, layout.backgroundColor.

The difference is how JavaScript describes it. Screens are listed once in createNavigation, layouts are builders, and commands come from the screen, with no componentId to pass.

react-native-navigation
index.js
import {
Navigation,
} from 'react-native-navigation';

Navigation.registerComponent(
'Home',
() => Home,
);
Navigation.registerComponent(
'Details',
() => Details,
);

Navigation.events()
.registerAppLaunchedListener(() => {
Navigation.setRoot({
root: {
stack: {
children: [
{ component: { name: 'Home' } },
],
},
},
});
});
@apexnative/navigation
Navigation.ts
import {
createNavigation,
} from '@apexnative/navigation';

export const Navigation =
createNavigation({
screens: {
Home: HomeScreen,
Details: DetailsScreen,
},
root: 'Home',
});

On the right, screens names every screen, and root is what the window shows first: a stack with Home. The library sets the root at each launch itself, also when Android makes its activity again, so there is no launch listener to write.

What changes in the app​

react-native-navigationHere
ScreensNavigation.registerComponent(name, …), one call per screen.screens of createNavigation: a name and a component or defineScreen.
Which screencomponentId in the props, passed to every command.useNavigation() acts from the screen it is in; useScreen() gives { id, name }.
LayoutsNested JSON: stack, bottomTabs, sideMenu, component.Builders: Stack, Tabs, Tab, SideMenu, SplitView, Screen.
PropspassProps, untyped.props of the command, typed from the component.
Optionsstatic options, Navigation.mergeOptions.options of defineScreen, useScreenOptions, setOptions.
EventsNavigation.events() and the component's own methods.Hooks in the screen, listeners of createNavigation, navigation.on.
StartregisterAppLaunchedListener and setRoot.root or roots; willMount for the work before the first screen.

More on the model: Introduction.

The map​

Each piece of react-native-navigation, and what takes its place. The steps below show each one in code.

Layouts​

react-native-navigationHere
{ component: { name, passProps, options } }Screen(name, props).options(…), or the name alone.
{ stack: { children } }Stack(…); a screen named alone as a root is a stack.
{ bottomTabs: { children } } with options.bottomTabTabs(Tab(name).label(…).icon(…), …).
{ sideMenu: { left, center, right } }SideMenu({ left, center, right }).
{ splitView: { master, detail } }SplitView({ primary, secondary }).
{ externalComponent: { name } }nativeScreen(name) in screens.
Navigation.setRoot(…) after the launchroot; later, switchTo with a name of roots or a layout.

Commands​

react-native-navigationHere
push(componentId, layout)push(name, { props, options }).
pop, popTo, popToRootpop(), popTo(screenId), popToRoot().
setStackRoot(componentId, layout)setStack(…), or replace(name) for one screen.
showModal(layout)showModal(name, { props }): in a stack of its own by default.
dismissModal(componentId), dismissAllModals()dismiss() from the modal; dismissModal(id), dismissAllModals().
showOverlay, dismissOverlay, dismissAllOverlaysThe same names, with a screen name.
mergeOptions(componentId, options)setOptions(…) of the screen, or useScreenOptions.
mergeOptions with currentTabIndex, badge, sideMenu.left.visibleselectTab, setTabBadge, openMenu('left').

Options and events​

react-native-navigationHere
Navigation.setDefaultOptions(…)options, theme and presentation of createNavigation.
static optionsoptions of defineScreen: a plain object or the chain.
componentDidAppear, componentDidDisappearuseScreenAppear, useScreenDisappear, useFocusEffect.
navigationButtonPressedonPress of the button, or useNavigationButton(id, …).
searchBarUpdated, searchBarCancelPresseduseSearchBar({ onChange, onCancel }).
modalDismissed, modalAttemptedToDismissonDismiss of showModal; usePreventLeave.
Navigation.events().register…Listenerlisteners of createNavigation, navigation.on.

Setup​

react-native-navigationHere
import { Navigation } from 'react-native-navigation'navigation, hooks and builders from @apexnative/navigation.
AppRegistry left out of index.jsAppRegistry.registerComponent(name, Navigation) of the package.
RNNAppDelegate, import ReactNativeNavigationANNAppDelegate, import ApexNavigation.
com.reactnativenavigation.*dev.apexnative.navigation.*.
NavigationReactNativeHost in MainApplicationThe template's reactHost, and its loadReactNative(this) in onCreate.
RNNKotlinVersion in android/build.gradleNothing: the library reads kotlinVersion.

The move, step by step​

The steps go in the order an app moves: the native files and the entry point first, then the screens, then what the screens do.

Start with migrate​

migrate makes the first steps itself, and lists the rest place by place:

Terminal
npx apex-navigation migrate

It shows each change and asks before it writes, as setup does:

StepWhat migrate does
1. Swap the packageTakes react-native-navigation out of package.json and puts @apexnative/navigation in, then runs one install with the app's package manager, and the pods on a Mac (--skip-pods leaves them for later).
2. The native filescom.reactnativenavigation becomes dev.apexnative.navigation in MainApplication and MainActivity, without the NavigationPackage lines, as the navigation adds its package itself. RNNAppDelegate and import ReactNativeNavigation become ANNAppDelegate and import ApexNavigation in the Swift and Objective-C files next to the app delegate. The lines of the old library go from the Podfile and the Gradle files, and the Android theme and the back animation of setup come in.
3. Register the screens, 4. The first rootWhen index.js holds every registerComponent and the setRoot of registerAppLaunchedListener: a new Navigation.ts with the screens under the names they had and the root as Stack, Tabs and Tab, index.js that registers it, and navigation-env.d.ts.
  • Steps 3 and 4 move only in forms it reads: registerComponent('Name', () => Home), or a wrapper such as () => gestureHandlerRootHOC(Home), and a setRoot of screens by name, stacks and bottom tabs, a tab's bottomTab.text as its label. A screen registered in another file, a provider with a body, or a launch listener that does more leaves both steps to you, in the report.
  • MainApplication keeps its shape, with NavigationReactNativeHost, which builds as it is. The shorter form of the template is in step 2.
  • It doesn't run setup. Run it after, for the rest of its changes, such as the key of Info.plist that lets each screen set its status bar; doctor lists what is left.
  • It reads the code with TypeScript, so the app needs typescript among its dev dependencies.

Everything else is the report: each place in the files that import react-native-navigation, with the file and the line, the line as it is, its new form, and the step of this page, such as static options for step 5 or a command with componentId for step 6. The command changes none of these places, and exits with 1 while the report has any, as every command with files left to change by hand. With --json they are report: [{ file, line, step, what, before, after, docs }].

The steps below stay the reference for both: what migrate changed, and how to move each place of the report. Every option: The CLI.

1. Swap the package​

Remove react-native-navigation, add @apexnative/navigation, and install the pods again. From here on, each file that still imports the old package is an error in the editor: the list of what is left.

Terminal
npm uninstall react-native-navigation
npm install @apexnative/navigation
cd ios && pod install

2. The native files​

The old library already changed the same files this one needs, so each change is small. On iOS the app delegate extends ANNAppDelegate in place of RNNAppDelegate; its body stays as it was.

react-native-navigation
AppDelegate.swift
import ReactNativeNavigation

@main
class AppDelegate: RNNAppDelegate {
// …
}
@apexnative/navigation
AppDelegate.swift
import ApexNavigation

@main
class AppDelegate: ANNAppDelegate {
// …
}

On Android the activity keeps its class name; only the import changes.

MainActivity.kt
import dev.apexnative.navigation.NavigationActivity

class MainActivity : NavigationActivity()

The application drops NavigationReactNativeHost and keeps the reactHost of the React Native template. react-native-navigation loaded React Native itself; the navigation leaves it to the template's loadReactNative(this) in onCreate, which migrate adds.

MainApplication.kt
import com.facebook.react.PackageList
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import dev.apexnative.navigation.NavigationApplication

class MainApplication : NavigationApplication() {
override val reactHost: ReactHost by lazy {
getDefaultReactHost(
context = applicationContext,
packageList = PackageList(this).packages,
)
}

override fun onCreate() {
super.onCreate()
loadReactNative(this)
}
}

Then run setup. It makes the changes these files don't cover: the app's Android theme inherits Theme.ApexNavigation, AndroidManifest.xml turns on the system's back animation for the first screen, and Info.plist lets each screen set its status bar. It shows each change and asks before it writes.

Terminal
npx apex-navigation setup
warning

setup finds NavigationActivity and NavigationApplication by their names, and the old library used the same names. So it reports these two files as set up even with the old imports in them. migrate changes the imports; in a move by hand, change them as above, and check that no com.reactnativenavigation is left.

What each file does and why: What setup changes.

3. Register the screens​

Each registerComponent becomes one line of screens. A screen with options or providers moves them next to its component, in step 5 and step 11.

react-native-navigation
Navigation.registerComponent(
'Home',
() => Home,
);
Navigation.registerComponent(
'Profile',
() => Profile,
);
Navigation.registerComponent(
'Settings',
() => Settings,
);
@apexnative/navigation
Navigation.ts
createNavigation({
screens: {
Home: HomeScreen,
Profile: ProfileScreen,
Settings: Settings,
},
// …
});
  • Keep the old names while you move. A name with dots, such as 'app.Home', works as a quoted key, so the layouts and commands still match; rename later, and TypeScript finds every use.
  • The component gets its props, nothing else. There is no componentId prop: the screen's id comes from useScreen(), and the commands from useNavigation().
  • A screen loaded later goes as { load: () => import('./Settings') }, in place of a lazy component provider. See Loading a screen later.

4. The first root, and the entry point​

The layout of setRoot becomes root. The builders are shorter than the JSON and check the screen names and props.

react-native-navigation
Navigation.setRoot({
root: {
bottomTabs: {
children: [
{
stack: {
children: [
{
component: {
name: 'Home',
},
},
],
options: {
bottomTab: {
text: 'Home',
},
},
},
},
// Profile, the same way
],
},
},
});
@apexnative/navigation
Navigation.ts
export const Navigation =
createNavigation({
screens: {
Home: HomeScreen,
Profile: ProfileScreen,
},
root: Tabs(
Tab('Home').label('Home'),
Tab('Profile').label('Profile'),
),
});

Tab('Home') puts a stack around the screen, as the JSON did by hand, and the tab's item goes on the Tab. An sfSymbol of the old bottomTab becomes an icon of each platform: .icon({ ios: 'house', android: 'ic_home' }). More: Tabs.

tip

root and switchTo still take a root as JSON, { root: { stack: … } }, so a big layout can move as it is first and become builders later. TypeScript doesn't check the names and props in JSON.

The entry point registers the navigation with AppRegistry of the package. Work that ran before setRoot, such as reading the session, goes to willMount: the splash screen stays until it is done.

index.js
import { AppRegistry } from '@apexnative/navigation';
import { name } from './app.json';
import { Navigation } from './Navigation';

AppRegistry.registerComponent(name, Navigation);

More: Starting the app.

5. Options next to the screen​

static options moves to defineScreen. A plain object of options goes there as it is, so an existing object can move unchanged; the chain is shorter for new code.

react-native-navigation
Details.tsx
const Details: NavigationFunctionComponent<
{ id: string }
> = ({ id }) => <Text>{id}</Text>;

Details.options = (props) => ({
topBar: {
title: { text: `Item ${props.id}` },
},
});

// in index.js
Navigation.registerComponent(
'Details',
() => Details,
);
@apexnative/navigation
Details.tsx
function Details({ id }: { id: string }) {
return <Text>{id}</Text>;
}

export const DetailsScreen =
defineScreen({
component: Details,
options: (s, props) =>
s.title(`Item ${props.id}`),
});

The chain and a plain object give the same options: s.title('Profile') is { topBar: { title: { text: 'Profile' } } }, and s.options({ … }) takes any options the chain has no modifier for. A static options left on a component does nothing here. More: The chain and plain objects.

6. Commands without componentId​

useNavigation() gives the commands of the screen the component is in, so none of them takes a componentId. A push names the screen and gives its props; TypeScript checks both.

react-native-navigation
Navigation.push(props.componentId, {
component: {
name: 'Details',
passProps: { id: '42' },
options: {
topBar: {
title: { text: 'Item' },
},
},
},
});

Navigation.pop(props.componentId);
@apexnative/navigation
const navigation = useNavigation();

navigation.push('Details', {
props: { id: '42' },
options: (s) => s.title('Item'),
});

navigation.pop();
  • Code outside the screens, such as a notification handler, imports navigation from the package. Its commands act where the user is: navigation.push pushes into the stack of the screen the user sees.
  • No command takes the id of a stack. A push into another tab selects it first: await navigation.selectTab('inbox'), then push.
  • Every command returns a promise that resolves once the move has ended, as before, and a command that fails rejects it.

All the moves: Moving between screens.

7. Modals and overlays​

showModal takes a screen name, and puts the screen in a stack of its own, so a modal has a top bar without a stack around it. dismiss() from any screen of the modal closes it.

react-native-navigation
Navigation.showModal({
stack: {
children: [
{
component: {
name: 'Settings',
},
},
],
},
});

// in Settings
Navigation.dismissModal(
props.componentId,
);
@apexnative/navigation
navigation.showModal('Settings', {
closeButton: true,
});

// in Settings
navigation.dismiss();

closeButton adds the system close button that dismisses the modal, in place of a left button with a handler of your own. modalPresentationStyle becomes style of showModal, and a sheet with detents is sheet: { detents: ['medium', 'large'] }. Overlays keep their command names: showOverlay('Toast'), dismiss() from the overlay. More: Modals, Overlays.

8. Buttons and the events of a screen​

A button of the top bar takes its own onPress, so one navigationButtonPressed handler that switched on buttonId goes away. The handler gets the screen's navigation.

react-native-navigation
Profile.options = {
topBar: {
rightButtons: [
{ id: 'edit', text: 'Edit' },
],
},
};

// in Profile
useEffect(() => {
const sub = Navigation.events()
.registerComponentListener(
{
navigationButtonPressed({
buttonId,
}) {
if (buttonId === 'edit') {
openEdit();
}
},
},
props.componentId,
);
return () => sub.remove();
}, []);
@apexnative/navigation
export const ProfileScreen =
defineScreen({
component: Profile,
options: (s) =>
s.rightButtons({
id: 'edit',
text: 'Edit',
onPress: ({ navigation }) =>
navigation.push('Edit'),
}),
});

The other events of a component become hooks of the screen. Each listens only to its own screen, while the component is mounted:

The component's methodThe hook
componentDidAppearuseScreenAppear, or useFocusEffect for work with a cleanup.
componentDidDisappearuseScreenDisappear.
componentWillAppearuseScreenEvent('screenWillAppear', …).
navigationButtonPressedonPress of the button, or useNavigationButton('edit', …).
searchBarUpdated, searchBarCancelPresseduseSearchBar({ onChange, onCancel }).
screenPoppeduseScreenEvent('screenPopped', …).

Events of the whole app, which Navigation.events() registered, go in listeners of createNavigation. They carry the screen as { id, name } in place of componentId and componentName:

Navigation.ts
createNavigation({
// …
listeners: {
// your own analytics
screenDidAppear: ({ screen }) => trackScreen(screen.name),
},
});

More: Bar buttons, Lifecycle and events.

9. Options of a shown screen​

Navigation.mergeOptions changed a screen's options from anywhere, by its id. Here a screen changes its own: from a handler with setOptions, or from its state with useScreenOptions.

react-native-navigation
useEffect(() => {
Navigation.mergeOptions(
props.componentId,
{
topBar: {
title: {
text: `${count} selected`,
},
},
},
);
}, [count]);
@apexnative/navigation
useScreenOptions((s) =>
s.title(`${count} selected`),
);

useScreenOptions builds the options on each render and applies them before the screen paints, when they changed. Most mergeOptions calls on containers have a command of their own now:

mergeOptions withHere
bottomTabs: { currentTabIndex: 1 }navigation.selectTab(1), or selectTab('inbox') by a tab's id.
bottomTab: { badge: '3' }navigation.setTabBadge(3, 'inbox'); null or 0 takes it away.
sideMenu: { left: { visible: true } }navigation.openMenu('left'), closeMenu().
bottomTabs: { visible: false } on a screenhideBottomTabs() in the screen's options.

More: Changing the options of a shown screen.

10. Leaving a screen​

The old way to keep the user on a screen was to turn the back off, popStackOnPress: false or swipeToDismiss: false, and handle the press yourself. Here usePreventLeave holds every way out at once, and calls its handler instead, so the screen can ask.

react-native-navigation
EditProfile.options = {
topBar: {
backButton: {
popStackOnPress: false,
},
},
hardwareBackButton: {
popStackOnPress: false,
},
};
// then the back button's id
// in navigationButtonPressed
@apexnative/navigation
usePreventLeave(changed, () => {
confirmLeave(() =>
navigation.goBack(),
); // your own dialog
});

While changed is true, the back button, the swipe back, the system back of Android and the swipe down of a modal call the handler. Commands aren't held, so goBack() after the user agrees leaves. More: Keeping the user on a screen.

11. Default options, the theme, providers​

setDefaultOptions becomes options of createNavigation, which takes the same object. The colors that most apps set there have a shorter place: the theme, whose colors can be { light, dark } and follow the system.

react-native-navigation
Navigation.setDefaultOptions({
topBar: {
background: {
color: '#FFFFFF',
},
title: { color: '#111111' },
},
layout: {
orientation: ['portrait'],
},
});
@apexnative/navigation
createNavigation({
// …
theme: {
colors: {
bar: '#FFFFFF',
text: '#111111',
},
},
options: (s) =>
s.orientation('portrait'),
});
  • What every push or modal starts from, such as an animation, goes in presentation; the command's own settings go over it.
  • layout.direction becomes direction of createNavigation, and navigation.setDirection at run time.
  • A provider that wrapped each screen in registerComponent, such as a store's, goes to screenProvider; one React tree for every screen is appProvider. See One tree.

More: Theme and context, Where a screen gets its options.

12. Signed in and signed out​

An app that called setRoot again after the sign-in lists both roots and switches between them. The first one comes from the context, which willMount fills before the first screen.

react-native-navigation
Navigation.events()
.registerAppLaunchedListener(
async () => {
const signedIn =
await isSignedIn();
Navigation.setRoot(
signedIn ? mainRoot : loginRoot,
);
},
);

// after the sign-in
Navigation.setRoot(mainRoot);
@apexnative/navigation
createNavigation({
// …
roots: { login: 'Login', main },
context: { signedIn: false },
willMount: async () => {
navigation.setContext({
signedIn: await isSignedIn(),
});
},
initialRoot: (context) =>
context.signedIn ? 'main' : 'login',
});

// after the sign-in
await navigation.switchTo('main');

Here main is a layout such as the Tabs(…) of step 4. A switch closes the modals and keeps the overlays. More: Switching roots.

13. Deep links​

Navigation.setLinking becomes linking of createNavigation. The old config is a tree of screens, and a matched link opens in a modal by default; here a route per path pattern says what the link does, and a screen name pushes it where the user is.

react-native-navigation
Navigation.setLinking({
prefixes: ['myapp://'],
screens: {
Profile: 'user/:userId',
Settings: 'settings',
},
});

// after the sign-in
Navigation.setLinkingReady(true);
@apexnative/navigation
createNavigation({
// …
linking: {
prefixes: ['myapp://'],
when: (context) =>
context.signedIn,
routes: {
'user/:userId': 'Profile',
settings: 'Settings',
},
},
});

when takes the place of setLinkingReady: a link waits until it is true, and opens on its own once the context changes. A route can show a modal itself with open, or make the whole first root of a launch with start. The native declarations, the scheme and the associated domains, stay as they are. More: Deep links.

14. Native components​

An externalComponent becomes a native screen: registered natively under a name, and listed in screens with nativeScreen, so commands and layouts name it as any other screen.

Navigation.ts
screens: {
// …
Map: nativeScreen('MapScreen'),
},

On iOS the creator returns a view controller, as before, through ApexNavigation.registerNativeScreen. On Android it returns a view, since this library has no fragments. A screen in SwiftUI or Compose works the same way. More: Native screens.

15. Check and clean up​

Search the app for react-native-navigation and componentId: once neither is left, run doctor. It checks React Native, the native files and the pods, and warns while react-native-navigation is still among the dependencies.

Terminal
npx apex-navigation doctor

Then the typed commands: one declaration ties navigation.push('Details', { props }) to the screens of Navigation.ts, so a wrong name or a missing prop is an error in the editor.

navigation-env.d.ts
declare module '@apexnative/navigation' {
interface Register {
app: typeof import('./Navigation').Navigation;
}
}
export {};

More: Typed commands. NavigationFunctionComponent and NavigationProps go away with the old package: a screen is a plain component of its props.

Option keys​

Most options kept their path, so an options object of the old library is valid here as it is. These are the large groups that stay:

  • topBar: title, subtitle, backButton, leftButtons, rightButtons, background, largeTitle, searchBar, visible, drawBehind.
  • The containers: bottomTabs, bottomTab, sideMenu, splitView, modal, overlay, fab.
  • The screen and the system: layout.backgroundColor, layout.orientation, statusBar, navigationBar, modalPresentationStyle, popGesture.
  • Motion: animations, with push, pop, setRoot, showModal and dismissModal.

Colors take the same values, a string or { light, dark }.

Renamed or moved​

react-native-navigationHere
sfSymbol, sfSelectedSymbol, an icon { system }icon: { ios: 'house', android: 'ic_home' }: a symbol or an image per platform.
bottomTab.popToRootbottomTab.popToRootOnPress, or Tab(…).popToRootOnPress().
topBar.searchBarPlaceholder and the other searchBar… keystopBar.searchBar.placeholder, .tintColor, .hideOnScroll.
layout.insets, layout.topMargin, layout.fitSystemWindowslayout.safeAreaEdges, or s.safeArea(…).
layout.directiondirection of createNavigation.
windowwindow of createNavigation (iOS).
A button's showAsActionpinned: true keeps a button in the bar; the others go to the overflow menu when space is short.

Removed​

react-native-navigationWhat to do here
backButton.popStackOnPress, hardwareBackButton.popStackOnPress, hardwareBackButton.dismissModalOnPress, modal.swipeToDismissusePreventLeave: see step 10.
preview, TouchablePreviewusePreview (iOS): a long press on a view shows a screen small, with a menu.
backgroundImage, rootBackgroundImageAn image in the screen's content.
bottomTabs.animateTabSelection, bottomTabs.blurRadius, bottomTabs.preferLargeIconsNo option; the tab bar looks as the platform draws it.

The whole list of options, with what each does on each platform: Where each option is described.

What has no direct equivalent​

react-native-navigationWhat to do here
Navigation.updatePropsProps are given once. What changes goes in the screen's state, or the app's context or store.
Navigation.constants()useSafeAreaInsets() of a screen (the bottom is not padded by default: a list adds insets.bottom to its bottom padding): what the bars and the system still cover of its content, measured for that screen; 0 on an edge the screen keeps clear itself. A screen that needs the height of its top bar goes under it (drawBehind) and reads the top inset.
componentId in a class componentHooks need a function component: wrap the class in one that passes useNavigation() down as a prop.
topTabsNo container for it. A pager component inside one screen does the same.
Navigation.handleDeepLink(url)Run the command the route would run, such as navigation.push('Profile', { props }).
getLaunchArgsRead the launch arguments in native code, and pass what JavaScript needs through a module of your own.
addOptionProcessor, addLayoutProcessorA function of your own that builds the options, or groups of screens that share them.
registerCommandListener, registerCommandCompletedListenerawait the command's promise; stateChanged tells what the user sees after it.
The Modal componentshowModal with a screen, or React Native's Modal inside a screen.