How can I pass parameters to another tab navigation screen - react-native

Hi guys I'm still new to react native, I wanted to ask how can I pass a parameter to another screen? I'm currently doing a login system which going to access the email of the user and show their email on their profile page after they logged in. I've tried { this.props.navigation.state.params.Email } in the profile.js but it shows an error says that
TypeError: undefined is not an object (evaluating 'this.props.navigation.state.params')
I saw some related solutions as well but those were for stack navigator but I'm using bottom tab navigation so I wasn't sure if they work in the same way.
login.js
this.props.navigation.navigate('Profile', { Email: email });
app.js
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={getTransaction} />
<Tab.Screen name="addTransaction" component={addTransaction} />
<Tab.Screen name="Register" component={register} />
<Tab.Screen name="Login" component={login} />
<Tab.Screen name="Profile" component={profile} />
</Tab.Navigator>
</NavigationContainer>
);
}

in your Profile screen page:
export const profile = ({route}) => {
const { Email } = route.params;
}
Then you can use 'Email' as a regular constant.

https://reactnavigation.org/docs/params/
I believe you should get the params from props.router instead of props.navigation.

Related

React Navigation 6.x Initial Route Not Working

I'm using React Navigation 6.x's linking with Expo so that when a user clicks on a notification they are directed to the appropriate part of my application to interact with the new information. When my app is backgrounded (running in the background) and a user clicks on a notification they are redirected to the screen they need to be at, which works perfectly fine. However, when the app is killed and the user clicks on a notification, they are taken directly to the screen for which the url is provided and they cannot press back to navigate elsewhere in my application. I tried to resolve this by using the initialRouteName prop like is shown in the docs (link: https://reactnavigation.org/docs/configuring-links/#rendering-an-initial-route), but I cannot get it to work. For further clarification, when I mentioned above that I am able to get linking working it is in relation to the direct SettingsScreen, AddFriendScreen, and MessagingScreen links. What I cannot get working is the specific block of code inside the liking object that starts with HomeScreen. What I believe may be causing the issue is that I am trying to set my initialRoute as a screen within HomeScreen's Tabs.Navigator and then trying to route to a screen within my Stack.Navigator. However, the docs show that this is possible (link: https://reactnavigation.org/docs/configuring-links/#rendering-an-initial-route).
My code:
const linking = {
prefixes: [prefix],
config: {
screens: {
HomeScreen: {
initialRouteName: "Chats",
screens: {
AddFriendScreen: "addFriend",
CreateChatScreen: "createChatScreen",
Friends: "friends",
MessagingScreen: 'messagingScreen/:chatRoomId'
}
},
SettingsScreen: "SettingsScreen",
AddFriendScreen: "AddFriendScreen",
MessagingScreen: 'MessagingScreen/:chatRoomId'
},
}
};
<NavigationContainer linking={linking} theme={MyTheme} >
<Stack.Navigator>
{!authState.value ?
<>
<Stack.Screen name="LoginScreen" component={LoginScreen} />
<Stack.Screen name="SignUpScreen" component={SignUpScreen} />
<Stack.Screen name="ForgotPasswordScreen" component={ForgotPasswordScreen} />
</>
:
<>
<Stack.Screen name="HomeScreen" component={HomeScreen} />
<Stack.Screen name="MessagingScreen" component={MessagingScreen} />
<Stack.Screen name="SettingsScreen" component={SettingsScreen} />
<Stack.Screen name="CreateChatScreen" component={CreateChatScreen} />
<Stack.Screen name="AddFriendScreen" component={AddFriendScreen} />
</>
}
</Stack.Navigator>
</NavigationContainer>
const HomeScreen = () => {
return (
<Tabs.Navigator>
<Tabs.Screen name="Chats" component={ChatScreen} />
<Tabs.Screen name="Friends" component={FriendsScreen} />
<Tabs.Screen name="Profile" component={ProfileScreen} />
</Tabs.Navigator>
)
}
Hmm, I would put any screen that I would like to access in multiple navigators at the root level so that they can both reach it.
For my own project, I have a root stack with a dedicated auth stack and an app/home stack (which is a tab nav like your HomeScreen). And outside that I have all my modal and root screens that I'd like other navigators to access (Because I really have two Home tab navigators the user can switch between.)
Idk if putting all of your screens listed after HomeScreen outside of that object will help your situation, but you can try that.

How to specify a default screen for react native stack navigator?

I want to navigate between two screens in my RN application: Daily and AllTodos. I want to make sure that when the navigator renders Daily by default. This is the code which I have used which accords the documentation :
const StackNavigator = ({component}) => {
return (
<NavigationContainer independent={true}>
<Stack.Navigator initialRouteName="Daily">
<Stack.Screen
name="Daily"
component={Daily}
options={{headerShown: false}}
/>
<Stack.Screen
name="AllTodos"
component={AllTodos}
options={{headerShown: false}}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
But still AllTodos page is rendered by default. Where am i going wrong?
You don't need to destructure the 'component' props. Take it off.
const StackNavigator = ({component}) // take off the component props => {

How to create and use many Tab Navigator in react native?

I'm trying to create differents bottom tab navigator in a single application in react native.
At the moment I can create and use a single one properly, but I'd like to display another one when I've connected to the application by the authentification form.
Is it possible ?
Here is an example of my code that will help you to understand what I'd like to do if you didn't :
export default function AppNavigation() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="SignUp" component={SignUpFunction} />
<Tab.Screen name="SignIn" component={SignInFunction} />
</Tab.Navigator>
</NavigationContainer>
);
}
and I would like to create another one like :
export default function AppNavigation() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="SignUp" component={SignUpFunction} />
<Tab.Screen name="SignIn" component={SignInFunction} />
</Tab.Navigator>
<Tab.Navigator>
<Tab.Screen name="Profil" component={ProfilPageFunction} />
</Tab.Navigator>
</NavigationContainer>
);
}
My problem is that it is not possible having two Tab.Navigator
I don't find documentation talking about it on the internet. If you guys have one or are able to explain me how to do it would be awesome.
By mentioning 'Different tab navigators' I'll assume that you want to have tab navigators in different screens.
There are options to do this.
First one based on the tab names that you have provided, you are trying to have an authentication flow, the approach would be to render tabs based on the login state.
export default function AppNavigation() {
return (
<NavigationContainer>
{!isloggedIn?(<Tab.Navigator>
<Tab.Screen name="SignUp" component={SignUpFunction} />
<Tab.Screen name="SignIn" component={SignInFunction} />
</Tab.Navigator>):
(<Tab.Navigator>
<Tab.Screen name="Profil" component={ProfilPageFunction} />
</Tab.Navigator>)}
</NavigationContainer>
);
}
Here isloggedIn will come from your context or state or however you manage the state.
Second option is to have multiple screen in a stack navigator with tab navigators, this is called nesting navigators
inside each screen
function Home() {
return (
<Tab.Navigator>
<Tab.Screen name="Feed" component={Feed} />
<Tab.Screen name="Messages" component={Messages} />
</Tab.Navigator>
);
}
//inside the NavigationContainer
<Stack.Screen name="Home" component={Home} />
Both approaches would work

React Native Navigation pass dynamic data when rendering

changeTheme(){
this.setState({darktheme:!this.state.darktheme})
}
render()
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} darkT={this.state.darktheme==true} />
<Stack.Screen name="Settings" component={SettingsScreen} changeTheme={this.changeTheme} darkT={this.state.darktheme==true} />
</Stack.Navigator>
</NavigationContainer>
);
}
In the settings page. I want to change the theme using this.props.changeTheme() it is supposed to change the state of the app and the whole app will re-render. But it doesn't work like that, the theme is not being changed. What am I doing wrong here?
When I log this.props.darkT it returns false even after I called the function changeTheme()
You can try this:
<Stack.Screen name="Settings">
{ () => <SettingsScreen darkT={!!this.state.darkTheme} changeTheme={this.changeTheme} /> }
</Stack.Screen>
In the Settings screen darkT and changeTheme will be available as props so you can access with this.props.darkT and this.props.changeTheme

react navigation, get name of nested route

I have a nested drawer navigator below, I am using a custom component in the header:
header: props => {
return <DrawerHeader {...props} />;
},
When I try and access from props the current route in my header, like below, the title is undefined, how can I get the current route?
render() {
const {
navigation,
videos,
search: {term},
scene: {
route: {routeName: title}, // undefined
},
} = this.props;
return (
<View>
<View style={styles.container}>
Navigator:
function DrawerStack() {
return (
<Drawer.Navigator>
<Drawer.Screen
name="VideoEpisodesScreen"
component={VideoEpisodesScreen}
/>
<Drawer.Screen name="TestYourselfScreen" component={TestYourselfScreen} />
<Drawer.Screen name="MyResultsScreen" component={MyResultsScreen} />
<Drawer.Screen name="AboutScreen" component={AboutScreen} />
<Drawer.Screen name="TestsScreen" component={TestsScreen} />
<Drawer.Screen
name="BookmarkedVideosScreen"
component={BookmarkedVideosScreen}
/>
</Drawer.Navigator>
);
}
export default function AppNavigator() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={stackOptions}
/>
<Stack.Screen
name="Drawer"
component={DrawerStack}
options={drawerOptions}
/>
<Stack.Screen
name="MyResultsScreen"
component={MyResultsScreen}
options={options}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
Funnily enough I had the exact same problem and I found your question after it was just an hour old. Essentially the problem is that React Navigation will only give you the current route of the navigator containing the header. If you have a nested navigator, you won't be able to get it.
It looks like this is somewhat intentional, but I've found that by manually querying the state of the navigator, you can drill down to the "deepest" navigator route. Note that while this works for react-navigation 5, it may not work in the future.
You can iteratively query the nested state like this:
const state = navigation.dangerouslyGetState();
let actualRoute = state.routes[state.index];
while (actualRoute.state) {
actualRoute = actualRoute.state.routes[actualRoute.state.index];
}
Note that this is extremely brittle, but it seems to work good enough for my use cases. You should consider creating an issue/feature request on the react-navigation repository for supporting this use case officially.
React Navigation v6 solution:
A nested route object can be discovered through parent Screen listeners. It's given in a callback argument, and can be passed to getFocusedRouteNameFromRoute to get the route name. In the example shown below, I chose to utilize it during the event 'state' (whenever state changes in the nested stack), but you can use it elsewhere if you want.
<Screen
listeners={({ route }) => ({
state: () => {
const subRoute = getFocusedRouteNameFromRoute(route)
// Your logic here //
}
})}
/>
I think in react-navigation 5, you can access route from this.props
const { route } = this.props;