React Navigation has a dynamic API which makes it possible to achieve advanced and use cases. But it can result in additional boilerplate and duplication. The goal of this static API is to provide a simpler API for simple use cases.
const MyNavigation = createNavigation({
// Type of the navigator, takes the 'createXNavigator' function from respective package
type: createStackNavigator,
// Any props accepted by the navigator
initialRouteName: 'Home',
keyboardHandlingEnabled: false,
// List of screens in the navigator
screens: {
Home: {
// Screens with nested navigators need to specify `type` and `screens` instead of `component`
type: createBottomTabNavigator,
screens: {
Feed: {
component: FeedScreen,
options: {
title: 'Feed',
},
},
},
},
Profile: {
// The component to render for this screen
component: ProfileScreen,
// Options for the screen
options: ({ route, data }) => ({
title:
// The additional `data` parameter can be used to configure the screen based on dynamic data
data.me === route.params.username
? 'My Profile'
: `@${route.params.username}'s Profile`,
}),
// ID for navigating to new screens
getId: ({ route }) => route.params.username,
// Path for linking integration
path: 'profile/:username',
},
// It's possible to specify a component directly
Settings: SettingsScreen,
},
});
The MyNavigation
component can be directly used or rendered to pass additional props to the NavigationContainer
. It takes the same props as the NavigationContainer
component except linking
, which is automatically configured based on the path
properties in the configuration. In addition, it also accepts a data
prop that can be used to for dynamic options.
export default function App() {
return (
<MyNavigation
data={{ me: 'jane' }}
onStateChange={() => {
// Do something on navigation
}}
/>
);
}
The TypeScript setup is different from how it's done with the regular API. Each screen component needs to specify the type of the route
prop:
type Props = {
route: {
params: {
username: string;
};
};
};
function ProfileScreen({ route }: Props) {
// ...
}
The type of Props
can be specified with the StaticScreenProps
alias in a simpler way:
type Props = StaticScreenProps<{
username: string;
}>;
The navigation
prop isn't passed to the screen component with the static configuration. Users need to use the useNavigation
hook instead. To TypeCheck the useNavigation
hook, a default type can be specified as follows:
declare global {
namespace ReactNavigation {
interface RootParamList extends StaticParamList<typeof Navigation> {}
}
}
Since the navigation is static, it's not possible to conditionally render a screen based on the authentication state. Instead, the condition can be specified with the if
property in the config:
type Data = {
isSignedIn: boolean;
};
const MyNavigation = createNavigation<Data>({
// ...
screens: {
Login: {
if: ({ isSignedIn }) => !isSignedIn,
component: LoginScreen,
},
Home: {
if: ({ isSignedIn }) => isSignedIn,
component: HomeScreen,
},
},
});
export default function App() {
const { isSignedIn } = useAuth();
return <MyNavigation data={{ isSignedIn }} />;
}
Liked the idea, good API for simple use cases as you said.
Also liked the
path: 'profile/:username'
config. Seems intuitive. Not sure about theif
API. In the above example, ifisSignedIn
is true, can we specify to open theHomeScreen
by default (if there are multiple screens)? feels it'd be better to use the dynamic API for such cases imo.