- Published on
> I'm Really Excited About React Navigation v8
- Authors

- Name
- Mick MacCallum
- @0x7fs
I've been following the React Navigation v8 alpha closely, and I have to say, this is the release I've been waiting for. The headline features include truly native bottom tabs, dramatically improved TypeScript support, and finally a proper solution for deep linking to screens behind authentication. That last one has been a thorn in my side for years, and seeing it solved properly has me genuinely excited to upgrade.
Native Bottom Tabs
The Bottom Tab Navigator now uses native primitives from react-native-screens by default, and the difference is immediately noticeable. On iOS, your tab bar automatically gets the platform's liquid glass effect and buttery smooth native animations. Android gets its own native treatment. The result looks and feels indistinguishable from a fully native app, without any extra configuration on your part.
If you prefer the previous JavaScript-based implementation (maybe you need heavy customization), you can opt out by setting the implementation prop to custom. But for most apps, the native version should just work and look better doing it.
Accessing Parent Screens
One of the more annoying patterns in React Navigation has always been passing data down through nested navigators. If you have a screen inside a stack inside a tab navigator, getting access to the tab-level route params meant prop drilling or context workarounds.
v8 introduces a cleaner approach with parent-aware hooks:
// Get route params from a parent screen
const parentRoute = useRoute('ProfileStack')
const userId = parentRoute.params?.userId
// Access the parent navigator's navigation object
const parentNavigation = useNavigation('TabNavigator')
// Read state from a parent navigator
const tabIndex = useNavigationState('TabNavigator', (state) => state.index)
The string argument is the name you gave the parent screen when defining your navigator. This makes it explicit which parent you're reaching for, avoiding the ambiguity of just grabbing "the nearest parent."
TypeScript Gets Smarter
Previous versions required a lot of boilerplate to get proper type safety for your routes. You'd define a RootStackParamList, annotate every screen, and hope you kept it all in sync. v8 flips this around with automatic type inference.
The new createStackScreen() helper (and equivalents for other navigators) infers route param types from multiple sources. If your screen component has typed props, those become the param types. If you define a URL pattern like /users/:userId, the library automatically types userId as a string parameter. If you have a custom parse function, the return type becomes your params type.
This means less code and fewer opportunities for the types to drift from reality. The types come from the code itself rather than a parallel type definition you have to maintain.
Updating Params Without New Screens
Here's a scenario that's always been awkward: you have a list view with filters, and you want the back button to step through filter states. In v7 and earlier, you'd either push new screens (bloating your stack) or use setParams (which doesn't add history entries).
v8 adds pushParams, which updates the current screen's params while adding a new entry to the history stack:
navigation.pushParams({ filter: 'recent' })
The screen doesn't re-mount, but pressing back returns to the previous param state. This is particularly useful for web where users expect the browser's back button to work naturally with filter and search states.
Deep Linking Behind Auth Screens
This is the feature I'm most excited about. Deep linking in React Native has always struggled with conditional screens, and it's been one of those problems that every team eventually runs into and nobody has a clean solution for. If a user isn't logged in and you try to link to /profile/settings, the screen doesn't exist yet. v7 would either fail silently or navigate to the wrong place, leaving users confused about why the link they tapped did nothing useful.
v8 finally solves this with routeNamesChangeBehavior: 'lastUnhandled'. When enabled, navigation actions that can't be completed get stored instead of dropped. The navigator remembers where you were trying to go. Once the user logs in and those screens become available, the stored action executes automatically, and the user lands exactly where they intended.
<Stack.Navigator screenOptions={{ routeNamesChangeBehavior: 'lastUnhandled' }}>
{isLoggedIn ? (
<>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</>
) : (
<Stack.Screen name="Login" component={LoginScreen} />
)}
</Stack.Navigator>
With this configuration, a deep link to /settings will wait until isLoggedIn becomes true, then navigate. No more lost deep links. No more hacky workarounds involving global state and useEffect chains. No more support tickets from users wondering why the link in their email didn't work. This single feature is going to save teams countless hours of frustration.
State Persistence Made Simple
Persisting navigation state across app restarts has always been possible but tedious. You'd subscribe to state changes, serialize to AsyncStorage, load on startup, and handle various edge cases around stale state and invalid routes.
v8 adds a persistor prop that handles all of this:
import { createNavigationPersistor } from '@react-navigation/native'
const persistor = createNavigationPersistor({
storage: AsyncStorage,
})
function App() {
return <NavigationContainer persistor={persistor}>{/* ... */}</NavigationContainer>
}
The library handles serialization, storage, hydration, and even deals with edge cases like screens that no longer exist in your navigator structure.
Trying It Out
Since v8 is still in alpha, install with the @next tag:
npm install @react-navigation/native@next @react-navigation/stack@next
The API is largely compatible with v7, so upgrading an existing app shouldn't require major refactoring. That said, it's alpha software. Expect some rough edges and breaking changes before the stable release. But if you've been battling the same deep link frustrations I have, it's absolutely worth spinning up a branch and taking v8 for a test drive. I think you'll be as impressed as I am.
The full release notes cover additional changes around theming (including support for PlatformColor and CSS custom properties for web) and various smaller improvements. Check the official announcement for the complete details.
// Continue_Learning
Configuring Claude Code Permissions for React Native Development
React Native projects require running lots of shell commands. Here's how to configure Claude Code's permission system so you're not constantly approving the same operations.
Fixing 16KB Page Alignment Errors in React Native for Android
Google Play now requires 16KB page size support for Android apps. Here's how to fix alignment errors in your React Native project before your next release gets rejected.
Automatically Switch Node Versions with nvm for React Native Projects
Avoid cryptic build failures by setting up nvm to automatically use the right Node version when you cd into a project.
// Stay Updated
Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.