I'm using the new Static API of React Navigation version 7, and I'm struggling to wrap a nested navigator in a context.
My app shows the HomeScreen
with a button that can modally present the ProfileScreen
. This is wrapped in it's own native stack navigator called ProfileStack
. All screens within the ProfileStack
should be able to access ProfileProvider
but the HomeScreen
shouldn't.
Here's the code:
// Screens
function HomeScreen() {
const navigation = useNavigation();
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text>Home Screen</Text>
<Button
title="Show Profile modal"
onPress={() => navigation.navigate('ProfileStack')}
/>
</View>
);
}
function ProfileScreen() {
const navigation = useNavigation();
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text>Profile</Text>
<Button
title="Go to More Profile"
onPress={() =>
navigation.navigate('ProfileStack', {screen: 'MoreProfile'})
}
/>
</View>
);
}
function MoreProfileScreen() {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text>More Profile</Text>
</View>
);
}
// Context
type ProfileContextType = {
name?: string;
setName: (name: string) => void;
};
const ProfileContext = React.createContext<ProfileContextType | undefined>(
undefined,
);
const ProfileProvider = ({children}: {children: React.ReactNode}) => {
const [name, setName] = React.useState<string>();
return (
<ProfileContext.Provider value={{name, setName}}>
{children}
</ProfileContext.Provider>
);
};
// Navigators
const ProfileStackNavigator = createNativeStackNavigator({
screens: {
Profile: ProfileScreen,
MoreProfile: MoreProfileScreen,
},
});
const RootStackNavigator = createNativeStackNavigator({
screens: {
Home: HomeScreen,
ProfileStack: {
screen: ProfileStackNavigator,
options: {
presentation: 'modal',
headerShown: false,
},
},
},
});
const Navigation = createStaticNavigation(RootStackNavigator);
// App
function App(): React.JSX.Element {
return <Navigation />;
}
export default App;
How can I wrap ProfileStackNavigator
in ProfileProvider
so that both ProfileScreen
and MoreProfileScreen
can access the shared useState
of ProfileContext
?
You can use the layout param in createNativeStackNavigator
to wrap your navigator with other components.
const RootStackNavigator = createNativeStackNavigator({
screens: {
Home: HomeScreen,
ProfileStack: {
screen: ProfileStackNavigator,
options: {
presentation: 'modal',
headerShown: false,
},
},
},
layout: props => <ProfileProvider>{props.children}</ProfileProvider>
});
You can test it here: https://snack.expo.dev/Y8yZqOPGf1F1RmDemC5by