How to pass data through stack navigation to a specific screen on react native tabs? - react-native

I'm creating a bottom tabs in react native, which will have two screens Home and News.
But first, user will need to Sign In and the users data will be passed from the login screen to Home screen. How do i pass those data. By using
navigation.navigate('Home', {Name: Name});
I can successfuly retrieve the data in Homescreen, if I just use two screen(Login and Home in a stack). However, when I change to navigate to the tabs(which includes Home and News), it doesnt work with error 'Undefined is not an object(evaluating 'route.params.Name'.
May you guys show me which part did I miss?
Here's the app.js code.
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import HomeScreen from './homescreen';
import NewsScreen from './newsscreen';
import LoginScreen from './loginscreen';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { createStackNavigator } from '#react-navigation/stack';
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="News" component={NewsScreen} />
</Tab.Navigator>
);
}
const LoginStack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<LoginStack.Navigator screenOptions={{headerShown: false}}
initialRouteName="Login">
<LoginStack.Screen name="Login"component={LoginScreen}/>
<LoginStack.Screen name="MyTabs" component={MyTabs} />
</LoginStack.Navigator>
</NavigationContainer>
);
}
export default App;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Following is the homescreen code:
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function HomeScreen({route, navigation}) {
var Name = route.params.Name;
return (
<View style={styles.container}>
<Text>{Name}</Text>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
And finally here's the login code:
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
export default function LoginScreen({navigation}) {
const Name = 'Boy';
const login = () => {
navigation.navigate('MyTabs', {Name: 'Boy'});}
return (
<View style={styles.container}>
<Text>LoginScreen</Text>
<TouchableOpacity
onPress={login}
><Text
>LOGIN</Text>
</TouchableOpacity>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
})
I'm trying to learn how to pass data from a screen to another screen, in which the screen is located inside a tab stack. I hope you guys can understand the question and provide me with your opinion and solution. Thanks.

Output:
It needed just this little modification in MyTabs component:
function MyTabs({ navigation, route }) {
const { name } = route.params;
console.log(name);
return (
<Tab.Navigator>
<Tab.Screen
name="Home"
component={() => <HomeScreen name={route.params.name} />}
/>
<Tab.Screen name="News" component={NewsScreen} />
</Tab.Navigator>
);
}
Here is the working solution:
App.js
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
import HomeScreen from './home';
import NewsScreen from './newscreen';
import LoginScreen from './login';
// You can import from local files
const Tab = createBottomTabNavigator();
function MyTabs({ navigation, route }) {
const { name } = route.params;
console.log(name);
return (
<Tab.Navigator>
<Tab.Screen
name="Home"
component={() => <HomeScreen name={route.params.name} />}
/>
<Tab.Screen name="News" component={NewsScreen} />
</Tab.Navigator>
);
}
const LoginStack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<LoginStack.Navigator
screenOptions={{ headerShown: true }}
initialRouteName="Login">
<LoginStack.Screen name="Login" component={LoginScreen} />
<LoginStack.Screen name="MyTabs" component={MyTabs} />
</LoginStack.Navigator>
</NavigationContainer>
);
}
export default App;
LoginScreen
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
import React from "react";
export default function LoginScreen({ navigation }) {
const Name = 'Name From Login Screen';
const login = () => {
console.log("hi");
navigation.navigate('MyTabs', { name : Name });
}
return (
<View style={styles.container}>
<View style={styles.bottomView}>
<TouchableOpacity onPress={login} style={styles.button}>
<Text style={styles.textStyle}>LOGIN</Text>
</TouchableOpacity>
</View>
</View>
);
}
Home.js
import { Text, View, StyleSheet } from 'react-native';
import React from "react";
export default function HomeScreen({route, navigation, name}) {
console.log("***",name)
return (
<View style={styles.container}>
<Text style={styles.name}>{name}</Text>
</View>
);
}
Working Expo Snack example.

It's a little complicated to explain react native screens once you start combining bottomtabnavigator and stack navigator and even drawernavigation.
you may need to create stack navigation inside tab navigation like this.
//creating a separate stack within your tab
const HomeStack = createStackNavigator()
const HomeStackNavigator = () => {
return (
<HomeStack.Navigator screenOptions={{headerShown: false}}
initialRouteName="HomeScreen">
<HomeStack.Screen name="Home"component={HomeScreen}/>
</HomeStack.Navigator>
)
}
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator initialRouteName="HomeStackNavigator">
<Tab.Screen name="HomeStackNavigator" component={HomeStackNavigator} />
<Tab.Screen name="News" component={NewsScreen} />
</Tab.Navigator>
);
}
I believe, different navigators doesn't really talk to each other well. If you are using different navigator be prepare to nest stack navigators inside them.
The idea is, the parent of each display component should be a stack navigator. This will also allow you to better control your screenOptions.

Related

Correct way of presenting a new screen with a stack?

I have a signup page with 4 steps (4 separate screens). On the first page, the user enters their username in a field, on the second page a display name, on the third their birthday, and on the fourth their password.
Here's my current signup screen file:
import React from 'react';
import { View, Text, Button } from 'react-native';
const SignupScreen = () => {
return (
<View>
<Text>First step</Text>
<Button
title="Next step"
/>
</View>
);
}
export default SignupScreen;
But I'm a bit confused as to how to present the next screen when the user taps the Button. How do I create a Stack here? Or would I do it in the App.js file?
Here is my App.js:
import { StatusBar } from 'expo-status-bar';
import { FlatList, StyleSheet, Text, View, TouchableHighlight } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import {
RootStack,
TabsStack,
SignupStack
} from './navigation/navigation';
export default function App() {
return (
<NavigationContainer>
<RootStack.Navigator>
<RootStack.Screen
name="Tabs"
options={{ headerShown: false }}
component={TabsStack}
/>
<RootStack.Screen
name="SignupStack"
options={{ headerShown: false }}
component={SignupStack}
/>
</RootStack.Navigator>
</NavigationContainer>
);
}
And here is my navigation.js file:
import React from 'react';
import { FlatList, StyleSheet, Text, View, TouchableHighlight } from 'react-native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import SignupScreen from '../screens/SignupScreen';
export const RootStack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
const SignupNav = createNativeStackNavigator();
export const TabsStack = () => (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="History" component={SecondScreen} />
<Tab.Screen name="Third" component={ThirdScreen} />
<Tab.Screen name="Fourth" component={FourthScreen} />
</Tab.Navigator>
);
export const SignupStack = () => (
<SignupNav.Navigator>
<SignupNav.Screen
name="Signup"
component={SignupScreen}
options={{ headerTitle: 'Sign up' }}
/>
</SignupNav.Navigator>
);
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home</Text>
</View>
);
}
function SecondScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Second</Text>
</View>
);
}
function ThirdScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Third</Text>
</View>
);
}
function FourthScreen({ navigation }) {
function onPressButton() {
navigation.navigate('SignupStack');
}
return (
<View>
<FlatList
data={[
{key: 'Signup'},
]}
renderItem={({item}) => <TouchableHighlight onPress={onPressButton} underlayColor="white"><Text>{item.key}</Text></TouchableHighlight>}
/>
</View>
);
}
What's the correct way of doing this?
Thank you
the best way that i know, make all the screen as component and import it in the signup screen
signup.js
/*
import all you component(pages) here...
*/
const [screen, setScreen] = useState(1)
{screen == 1 ? (
<ScreenOne
onNext={()=>setScreen(2)}
/>
) : screen == 2 ? (
<ScreenTwo
onNext={()=>setScreen(3)}
/>
) : screen == 3 ? (
<ScreenThree
onNext={()=>setScreen(4)}
/>
)
}
You can pass all your state and callback function from signup page to all the component get value from the component

How to use drawer for custom toolbar

Here is my drawerNavigator
import React from 'react';
import {createDrawerNavigator} from '#react-navigation/drawer';
import {
SafeAreaView,
Text,
View,
Button,
Image,
TouchableOpacity,
} from 'react-native';
import {DrawerActions} from '#react-navigation/native';
const Dashboard = React.lazy(() => import('../screens/Dashboard.js'));
const POSCatalog = React.lazy(() => import('../screens/POSCatalog'));
const Drawer = createDrawerNavigator();
const DrawerNavigator = () => {
return (
<Drawer.Navigator
screenOptions={{
drawerPosition: 'right',
// drawerType:"permanent",
headerTintColor: '#000000',
headerTitleStyle: {
fontWeight: 'bold', //Set Header text style
},
}}>
<Drawer.Screen
name="Home"
component={Dashboard}
options={{
headerStyle: {
backgroundColor: 'white',
},
headerShown: false,
headerTintColor: 'black',
headerLeft: false,
}}
/>
<Drawer.Screen name="POSCatalog" component={POSCatalog} />
</Drawer.Navigator>
);
};
export default DrawerNavigator;
Here is my App.js file
import 'react-native-gesture-handler';
import React, {Suspense} from 'react';
import {
SafeAreaView,
Text,
View,
Button,
Image,
TouchableOpacity,
} from 'react-native';
import {
NavigationContainer,
getFocusedRouteNameFromRoute,
} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {createDrawerNavigator} from '#react-navigation/drawer';
import DrawerNavigator from './navigation/DrawerNavigator';
const Dashboard = React.lazy(() => import('./screens/Dashboard.js'));
const CustomerDashboard = React.lazy(() =>import('./screens/CustomerDashboard'),);
const Splash = React.lazy(() => import('./screens/Splash'));
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const Loading = () => {
return <SafeAreaView>{/* <Text>Loading</Text> */}</SafeAreaView>;
};
const Routes = ({navigation}) => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Splash">
<Stack.Screen
name="Splash"
component={Splash}
options={{headerShown: false, gestureEnabled: false}}
/>
<Stack.Screen
name="Dashboard"
component={DrawerNavigator}
options={{headerShown: false, gestureEnabled: false}}
/>
<Stack.Screen
name="CustomerDashboard"
component={CustomerDashboard}
options={{headerShown: false}}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
class App extends React.PureComponent {
render() {
return (
<Suspense fallback={<Loading />}>
<Routes />
</Suspense>
);
}
}
export default App;
Here is my Dashboard code where I am passing navigation to Banking file
import React, {useState, useEffect} from 'react';
import {
StyleSheet,
SafeAreaView,
View,
TouchableOpacity,
} from 'react-native';
import Banking from '../screens/Banking';
const Dashboard = ({navigation}) => {
return (
<SafeAreaView style={{flex: 1}}>
<View style={styles.container}>
<Banking navigation={navigation} />
</View>
</SafeAreaView>
);
};
export default Dashboard;
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
});
I am implementing navigation drawer inside my react native application and I want to access drawer wherever in my application. Let's say drawer is available in dashboard page. Inside the dashboard I have another component called banking. Inside banking I have a button to open another component called customerDashboard. In customerDashboard I have a drawer icon in toolbar. If I click drawer icon in customerDashboard I want to open the drawer.
Notes:
Drawer is available in component A
In Component A calling another component called B
Inside Component B navigating to Component C
Inside Component C need to open drawer when icon is clicked in toolbar.

I am geeting error : ReferenceError: navigation is not defined in react native navigation. I am just learning react native

I am trying to learn react native but getting following error
ReferenceError: navigation is not defined
I am a beginner can you please guide me to solve this error.
I have also tried to change to functional component but getting same error.
I am using expo for learning purpose
import 'react-native-gesture-handler';
import React, { Component } from "react";
import { ActivityIndicator, StyleSheet, Text, View, Image, Button,ImageBackground } from "react-native";
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
class HomeScreen extends Component {
render() {
return (
<View style = {styles.container}>
<Text>Hello HomeScreen</Text>
<Button
title="Go to Profile"
onPress={() => navigation.navigate('Profile')}
/>
</View>
);
}
}
class Profile extends Component {
render() {
return (
<View style = {styles.container}>
<Text>Hello profile</Text>
</View>
);
}
}
const Stack = createStackNavigator();
class App extends Component {
render() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="HomeScreen">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profle" component={Profile} />
</Stack.Navigator>
</NavigationContainer>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems : 'center'
},
});
export default App;
You are using a class based component so use this.props.navigation
<Button
title="Go to Profile"
onPress={() => this.props.navigation.navigate('Profile')}
/>

React DrawerNavigation Is Not Working (Nothing Happens) While I Drag To Open Side Menu

I'm trying to introduce DrawerNavigation under StackNavigation. My StackNavigation is working fine. But when I'm dragging the screen DrawerNavigation is not working. Nothing happens...No errors also.
I am using TouchableOpacity for the list items. Though I don't think so, is there any chance it is occurring due to the first touch on list-item??? If not, then can anyone point me out what the issue is? I really appreciate any help you can provide.
I have given my Navigator.Js code here and a video Url to understand better what is happening for my case.
Video URL - https://drive.google.com/file/d/1MhD3gB8Pp4tqbXr1HktOPa-2xOqW0xoA/view?usp=sharing
Instead of wrapping DrawerNavigator inside StackNavigator, wrap your StackNavigator inside DrawerNavigator.
Working Example: Expo Snack
Output:
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createDrawerNavigator } from '#react-navigation/drawer';
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator();
const StackNav = () => {
return (
<Stack.Navigator>
<Stack.Screen name="Login" component={() => <Text>Login</Text>} />
<Stack.Screen name="Register" component={() => <Text>Register</Text>} />
</Stack.Navigator>
);
};
export default function App() {
return (
<View style={styles.container}>
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="Stack" component={StackNav} />
<Drawer.Screen
name="HomeNews"
component={() => (
<View style={styles.container}>
<Text>HomeNews</Text>
</View>
)}
/>
<Drawer.Screen
name="StateNews"
component={() => (
<View style={styles.container}>
<Text>StateNews</Text>
</View>
)}
/>
</Drawer.Navigator>
</NavigationContainer>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
});

React Native - Update text after clicking button

I want to update the text after clicking button.
But couldn't find a way to do this.
The code is like:
import * as React from 'react';
import { View, Button, Text } from 'react-native';
import { NavigationContainer, CommonActions } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
function HomeScreen({ navigation }) {
const state = {
user: 'test',
};
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>{state.user}'s profile</Text>
<Button
title="Change user param"
onPress={() =>
navigation.dispatch({
...CommonActions.setParams({ user: 'Wojtek' }),
})
}
/>
</View>
);
}
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Expo example
I've tried navigation.setParams() and this.setState(), they couldn't work with the code I attached above.
You have to use hooks in functional components. So the code would be something like this:
import * as React from 'react';
import { View, Button, Text } from 'react-native';
import { NavigationContainer, CommonActions } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
function HomeScreen({ navigation }) {
const [user, setUser] = React.useState('test');
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>{user}'s profile</Text>
<Button
title="Change user param"
onPress={() => setUser("keidakira") }
/>
</View>
);
}
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Check it's working at Expo Link