Need help using goBack() in react native - javascript

I am having trouble with the back button in the stack navigator. I am getting an error saying undefined is not an object (evaluating '_this.props'). if it works it goes back to a different tab in the bottom stack navigator. Like if I click on book a session and then I go to home and click back it will take me to book a session no matter what. Please help.
This is what I have so far:
function HomeScreen({ navigation }) {
return (
<WebView
source={{
uri: 'https://www.stoodnt.com/'
}}
style={{ marginTop: -120 }}
/>
);
}
const HomeStack = createStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home"
component={HomeScreen}
options={{
headerLeft: () => (
<HeaderBackButton
onPress={() => this.props.navigation.goBack(null)}
/>
),
}}
/>
</HomeStack.Navigator>
);
}
Bottom Navigator:
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'Home') {
iconName = focused
? 'ios-home'
: 'ios-home';
} else if (route.name === 'Book Session') {
iconName = focused ? 'ios-calendar' : 'ios-calendar';
}
else if (route.name === 'Blogs') {
iconName = focused ? 'ios-bookmark' : 'ios-bookmark';
}
else if (route.name === 'Online Courses') {
iconName = focused ? 'ios-book' : 'ios-book';
}
else if (route.name === 'Classes') {
iconName = focused ? 'ios-desktop' : 'ios-desktop';
}
return <Ionicons name={iconName} size={40} color={'orange'} />;
},
})}
tabBarOptions={{
activeTintColor: '#000000',
inactiveTintColor: '#616161',
labelStyle: {
fontSize: 10,
},
style: {
backgroundColor: '#F7F7F7',
},
}}
>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Book Session" component={BookStackScreen} />
<Tab.Screen name="Blogs" component={BlogStackScreen} />
<Tab.Screen name="Online Courses" component={OnlineStackScreen} />
<Tab.Screen name="Classes" component={ClassesStackScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}

try the below code :
function HomeScreen(props) {
return (
<WebView
source={{
uri: 'https://www.stoodnt.com/'
}}
style={{ marginTop: -120 }}
/>
);
}
const HomeStack = createStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home"
component={HomeScreen}
options={({ route, navigation }) => ({
headerLeft: () => (
<HeaderBackButton
onPress={() => navigation.goBack(null)}
/>
),
})}
/>
</HomeStack.Navigator>
);
}```

In functional components, you do not have access to "this". You should either pass navigation from the screen options or use useNavigation.
<HomeStack.Screen
...
options={({navigation}) => (
headerLeft: () => (
// you can use navigation.goBack() here
)
)}
or
// this should be added right under function HomeStackScreen,
// right above the return and you will be able to use it in the screens
const navigation = useNavigation()

Related

How do I add routes to my react native app navigation, but keep it out of my tab navigation?

I've watched tutorials and looked at the docs however I still don't get it, I need someone to explain using my situation/code.
My navigation setup is similar to Instagram.
Bottom tab navigation has Home/Search/Inventory/Profile.
Here is my navigation file:
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import { PresenceTransition, Text, View } from "native-base";
import Home from "../../screens/Home";
import Profile from "../../screens/Profile";
import InventoryIcon from "../svg/InventoryIcon";
import SearchIcon from "../svg/SearchIcon";
import UserIcon from "../svg/UserIcon";
import HomeIcon from "../svg/HomeIcon";
import Search from "../../screens/Search";
import Inventory from "../../screens/Inventory";
import authStore from "../../zustand/authStore";
import Login from "../../screens/Login/Login";
import { SafeAreaView } from "react-native-safe-area-context";
import { TouchableOpacity } from "react-native";
import userDataStore from "../../zustand/userDataStore";
import Avatar from "../Avatar";
const Tab = createBottomTabNavigator();
export default function BottomNavigation() {
const currentUser = authStore((state) => state.currentUser);
if (!currentUser)
return (
<SafeAreaView>
<Login />
</SafeAreaView>
);
return (
<Tab.Navigator
tabBar={(props) => <TabBar {...props} />}
initialRouteName="Home"
screenOptions={({ route }) => ({
headerShown: false,
tabBarStyle: {
elevation: 0,
borderTopWidth: 0,
backgroundColor: "#2563eb",
},
tabBarShowLabel: false,
})}
>
<Tab.Screen name="Home" component={Home} />
<Tab.Screen name="Search" component={Search} />
<Tab.Screen name="Inventory" component={Inventory} />
<Tab.Screen name="Profile" component={Profile} />
</Tab.Navigator>
);
}
function TabBar({ state, descriptors, navigation }) {
const currentUser = authStore((state) => state.currentUser);
const userData = userDataStore((state) => state.userData);
return (
<View className="bg-blue-600 py-4" style={{ flexDirection: "row" }}>
{state.routes.map((route, index) => {
const { options } = descriptors[route.key];
const isFocused = state.index === index;
let params;
if (route.name === "Profile") {
params = {
uid: currentUser?.uid,
};
}
const onPress = () => {
const event = navigation.emit({
type: "tabPress",
target: route.key,
});
if (route.name === "Profile" && !event.defaultPrevented) {
navigation.navigate(route.name, params);
return;
}
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name, params);
}
};
const onLongPress = () => {
navigation.emit({
type: "tabLongPress",
target: route.key,
});
};
return (
<TouchableOpacity
accessibilityRole="button"
accessibilityState={isFocused ? { selected: true } : {}}
accessibilityLabel={options.tabBarAccessibilityLabel}
testID={options.tabBarTestID}
onPress={onPress}
onLongPress={onLongPress}
style={{ flex: 1 }}
>
<View className="relative flex w-full flex-1 items-center justify-center">
<TabIcon
currentUserProfilePicture={userData?.profilePicture}
name={route.name}
/>
<PresenceTransition
visible={isFocused}
initial={{ opacity: 0, scale: 0 }}
animate={{
opacity: 1,
scale: 1,
transition: {
duration: 200,
},
}}
className="absolute -bottom-7 h-4 w-4 rounded-sm bg-white"
/>
</View>
</TouchableOpacity>
);
})}
</View>
);
}
function TabIcon({
name,
currentUserProfilePicture,
}: {
name: string;
currentUserProfilePicture: undefined | null | string;
}) {
if (name === "Home") {
return <HomeIcon svgClassName="text-white w-6 h-6" />;
}
if (name === "Search") {
return <SearchIcon svgClassName="text-white w-6 h-6" />;
}
if (name === "Collections") {
return <CollectionsIcon svgClassName="text-white w-6 h-6" />;
}
if (name === "Profile") {
return currentUserProfilePicture ? (
<Avatar
url={currentUserProfilePicture}
alt="Your profile"
className="h-6 w-6"
/>
) : (
<UserIcon svgClassName="text-white w-6 h-6" />
);
}
return null;
}
Now, the problem is I want to add a Settings screen. This screen shouldn't be in the bottom tab bar, it should only be navigated to from the Profile screen. If I add it to the navigation, it is automatically added.
I could do something like:
const hiddenRoutes = ["Settings"]
if (hiddenRoutes.includes(route.name) {
return;
}
But this seems quite hacky to me, I feel its wrong.
How should I best declare routes, but keep them out of the bottom tab navigation?
You will want to create another navigation layer for your profile screen
To make the stack navigation for the profile screen:
const ProfileStack = createNativeStackNavigator<ProfileStackParamList>();
function ProfileNavigator() {
return (
<ProfileStack.Navigator >
<ProfileStack.Screen
name={"Profile"}
component={Profile}
options={() => ({
title: "Profile",
})}
/>
<ProfileStack.Screen
name={"Settings"}
component={Settings}
options={() => ({
title: "Settings",
})}
/>
</ProfileStack.Navigator>
);
}
Then in where you are making your Tab navigator use this stack navigation in the component
<Tab.Screen name="Profile" component={ProfileNavigator} />

Detect internet connection in react native anywhere in screens

I'm confused on how can I show my customDialog whenever I don't have Internet connection to my app, Currently, I've only managed to show my customDialog within LoginScreen , I just want to show my custom dialog from different screen not only on LoginScreen whenever I don't have Internet connection, what is the best way to implement it ? should I put CustomDialog each of the screen?
Someone have the idea to implement this? need help
screens/LoginScreen
import NetInfo from "#react-native-community/netinfo";
import CustomAlert from '../components/CustomAlert';
const LoginScreen = ({navigation}) => {
const [modalVisible, setModalVisible] = useState(false);
const [internetCon, setNet] = useState(true);
React.useEffect(()=>{
checkInternetConnection();
}, [])
function checkInternetConnection() {
NetInfo.addEventListener(state =>{
if (state.isConnected==false){
setModalVisible(true);
setNet(false);
console.log("Connection types", state.type);
console.log("Your device appears to have no internet connectivity. Please check your connection settings and try again");
}
else{
console.log("Connected to internet?", state.isConnected);
}
});
}
return (
<ScrollView style={styles.container} >
{internetCon ===false ? //Check if Internet Existt
<CustomAlert
modalVisible={modalVisible}
setModalVisible={setModalVisible}
title={'Message'}
message={'Your device appears to have no internet connectivity. Please check your connection settings and try again'}
buttons={[{
text: 'Retry',
func: () => {checkInternetConnection();}
}]}
/>
:null}
</ScrollView>
);
};
export default LoginScreen;
navigation/AppStack.js
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
const FeedStack = ({navigation}) => (
<Stack.Navigator
screenOptions={{
headerShown: false
}}>
<Stack.Screen
name="test"
component={HomeScreen}
options={{
headerTitleAlign: 'center',
headerTitleStyle: {
color: '#2e64e5',
fontFamily: 'Kufam-SemiBoldItalic',
fontSize: 18,
},
headerStyle: {
shadowColor: '#fff',
elevation: 0,
},
headerRight: () => (
<View style={{marginRight: 10}}>
<FontAwesome5.Button
name="plus"
size={22}
backgroundColor="#fff"
color="#2e64e5"
onPress={() => navigation.navigate('AddPost')}
/>
</View>
),
}}
/>
<Stack.Screen
name="HomeProfile"
component={ProfileScreen}
options={{
title: '',
headerTitleAlign: 'center',
headerStyle: {
backgroundColor: '#fff',
shadowColor: '#fff',
elevation: 0,
},
headerBackTitleVisible: false,
headerBackImage: () => (
<View style={{marginLeft: 15}}>
<Ionicons name="arrow-back" size={25} color="#2e64e5" />
</View>
),
}}
/>
</Stack.Navigator>
);
const AppStack = () => {
const getTabBarVisibility = (route) => {
const routeName = route.state
? route.state.routes[route.state.index].name
: '';
if (routeName === 'Chat') {
return false;
}
return true;
};
return (
<Tab.Navigator
screenOptions={{
headerShown: false
}}
tabBarOptions={{
activeTintColor: '#2e64e5',
}}>
<Tab.Screen
name="Home"
component={FeedStack}
options={({route}) => ({
tabBarLabel: 'Home',
// tabBarVisible: route.state && route.state.index === 0,
tabBarIcon: ({color, size}) => (
<MaterialCommunityIcons
name="home-outline"
color={color}
size={size}
/>
),
})}
/>
<Tab.Screen
name="Messages"
component={MessageStack}
options={({route}) => ({
tabBarVisible: getTabBarVisibility(route),
tabBarIcon: ({color, size}) => (
<Ionicons
name="chatbox-ellipses-outline"
color={color}
size={size}
/>
),
})}
/>
</Tab.Navigator>
);
};
export default AppStack;
navigation/AuthProvider.js
export const AuthContext = createContext();
export const AuthProvider = ({children}) => {
const [user, setUser] = useState(null);
const [modalVisible, setModalVisible] = useState(false);
return (
<AuthContext.Provider
value={{
user,
setUser,
googleLogin: async () => {
try {
// Get the users ID token
const Token = await GoogleSignin.signIn();
const {idToken} = Token;
console.log("Processing");
console.log("ok");
// Create a Google credential with the token
const googleCredential = auth.GoogleAuthProvider.credential(idToken);
// Sign-in the user with the credential
await auth().signInWithCredential(googleCredential)
.catch(error => {
console.log('Something went wrong with sign up: ', error);
});
} catch(error) {
// console.log('Something went wrong with sign up: ', error);
}
},
}}>
{children}
</AuthContext.Provider>
);
};
Yo can try react-navigation modal: https://reactnavigation.org/docs/modal/

React Native tab navigator nested in stack navigator

I'm relatively new to React Native and am struggling with screens. I've gone through the nested navigation documentation (https://reactnavigation.org/docs/nesting-navigators/) which helped me setup the initial nav setup i have, but im having some issues.
I'm attempting to setup the app so it has the initial screen as a "Select User" which has no tab navigation. After selecting the user, you are redirected to a another screen which has tab navigation. I currently have it working however I am unable to access any route/props/params after the initial screen.
I've had to manually import navigation with import { useNavigation } from "#react-navigation/native"; and even though I'm providing params in the Navigation.push, trying to access {route} in my screens states that route is undefined.
My setup of the screens looks similar to below:
const Tab = createBottomTabNavigator();
const WelcomeStack = createStackNavigator();
const HomeStack = createStackNavigator();
const SettingsStack = createStackNavigator();
const Stack = createStackNavigator();
const WelcomeStackScreen = () => (
<WelcomeStack.Navigator>
<WelcomeStack.Screen
name="Welcome"
component={WelcomeScreen}
options={{ headerShown: false }}
/>
<WelcomeStack.Screen
name="SignUp"
component={SignUpScreen}
options={{ headerShown: false }}
/>
</WelcomeStack.Navigator>
);
const HomeStackScreen = () => {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen
name="Search"
component={SearchResultScreen}
options={({ navigation }) => ({
headerLeft: () => (
<Ionicons
name={"arrow-back"}
size={30}
color={colours.text}
style={{ paddingLeft: 15 }}
onPress={() => {
navigation.goBack();
}}
/>
),
})}
/>
<HomeStack.Screen
name="Select"
component={SelectScreen}
options={({ navigation, route }) => ({
title: route.params.name,
headerLeft: () => (
<Ionicons
name={"arrow-back"}
size={30}
color={colours.text}
style={{ paddingLeft: 15 }}
onPress={() => {
navigation.goBack();
}}
/>
),
})}
/>
<HomeStack.Screen name="Read" component={ReaderScreen} />
</HomeStack.Navigator>
);
};
function SettingsScreen() {
return (
<View
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
>
<Text>TBD</Text>
</View>
);
}
const SettingsStackScreen = () => (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
</SettingsStack.Navigator>
);
const TabNavigator = ({ route }) => (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
switch (route.name) {
case "Home":
iconName = focused ? "home" : "home-outline";
break;
case "Settings":
iconName = focused ? "list" : "list-outline";
break;
default:
break;
}
return <Ionicons name={iconName} size={size} color={color} />;
},
})}
tabBarOptions={{
activeTintColor: "tomato",
inactiveTintColor: "gray",
}}
>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Settings" component={SettingsScreen}/>
</Tab.Navigator>
);
export default function App() {
return (
<NavigationContainer theme={navThemeOverride}>
<Stack.Navigator>
<Stack.Screen name="Welcome" component={WelcomeStackScreen} />
<Stack.Screen
name="TabNavigator"
component={TabNavigator}
options={{ headerShown: false }}
navigationOptions={{ gesturesEnabled: false }}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
Below is a snippet from the Welcome screen navigation
navigation.push("TabNavigator", {
screen: "Home",
params: {
userId: userId,
},
});
Your Home screen you're trying to navigate to from your parent-tab-navigator ... is also a StackNavigator ... and you wanna navigate to Select screen I guess ... so there's an extra level needed for your navigation to work...
navigation.navigate('TabNavigator', {
screen: 'Home', // <--- StackNavigator
params: {
screen: 'Select', // <-- nested inside HomeStack
params: {
title: 'Your custom title for Select screen here ...',
},
},
});
Plus +
There's a double definition for route in your Tab navigator
const TabNavigator = ({ route }) => ( //<--- here
<Tab.Navigator
screenOptions={({ route }) => ({ // <- and here
Instead
function TabNavigator() {
return <Tab.Navigator screenOptions={({ route }) => ({})>{/* ...Tabs... */}</Tab.Navigator>;
}

How to override header title in react navigation 5

In my react native app i have stack navigator and tab navigator like:
const diagnoseNavigation = ({ navigation, language }) => {
return (
<Stack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: "#0089d8",
shadowOpacity: 0
},
headerTitleStyle: {
fontWeight: "bold",
color: "white",
textAlign: "center"
},
headerLeft: () => (
.......
)
}}
>
<Stack.Screen
name="Diagnose"
component={tabNav}
options={({ route, navigation }) => {
const routeName = getFocusedRouteNameFromRoute(route) ?? "Home";
switch (routeName) {
case "Screen1": {
return {
headerTitle:"Screen1",
headerRight: () => (
.......
)
};
}
case "Screen2": {
return {
headerTitle: "Screen2" //want to override this one
};
}
default: {
return {
headerTitle: "Home"
};
}
}
}}
/>
</Stack.Navigator>
);
};
Tab navigation:
const Tab = createBottomTabNavigator();
const tabNav = () => {
return (
<Tab.Navigator tabBarOptions={{ showIcon: true }}>
<Tab.Screen
name="Screen1"
component={Screen1Screen}
/>
<Tab.Screen
name="Screen2"
component={Screen2Screen}
/>
<Tab.Screen
name="Screen3"
component={recommendedNavigation}
/>
</Tab.Navigator>
);
};
Screen2
const Screen2Screen = ({ route, language }) => {
return (
<Stack.Navigator>
<Stack.Screen options={{ headerShown: false }} name="A" component={AScreen} />
<Stack.Screen
name="B"
component={BScreen}
options={() => {
return {
headerTitle: "ABC" //with this one
};
}}
/>
</Stack.Navigator>
);
};
In short i have stack navigatior, in that i have tab navigator. there are 3 tabs,what i want is in my tab 2(Screen2) there is a button when i click that button it should navigate to another page within the same tab.Then the title should be the "ABC" but it still shows "Screen2" under that ABC. ie, not overriding the header title?
Something like this:
You have to pass showLabel props to hide the header in your tababrOptions.
<Tab.Navigator tabBarOptions={{ showIcon: true , showLabel: false,
}}>

React Native Navigation v5 triggering a drawer from bottom tabs

Currently I am trying to tigger the drawer from the bottom nav as you can see here:
My current tabs is the following:
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused }) => {
let iconName;
switch (route.name) {
case 'Home':
iconName = 'window-maximize';
break;
case 'Purchases':
iconName = 'tags';
break;
case 'Notifications':
iconName = 'bell';
break;
case 'Checkout':
iconName = 'shopping-cart';
break;
case 'Orders':
iconName = 'dollar';
break;
case 'Menu':
iconName = 'navicon';
break;
}
return (
<Icon
name={iconName}
size={20}
color={focused ? 'blue' : 'grey'}
/>
);
},
})}
tabBarOptions={{
showLabel: false,
}}>
<Tab.Screen name="Home" component={LandingScreens} />
<Tab.Screen name="Purchases" component={PurchasesScreens} />
<Tab.Screen name="Notifications" component={Notifications} />
<Tab.Screen name="Checkout" component={CheckoutScreens} />
<Tab.Screen name="Orders" component={OrdersScreens} />
<Tab.Screen
name="Menu"
component={Drawer}
listeners={({ navigation }) => ({
tabPress: (e) => {
e.preventDefault();
},
})}
/>
</Tab.Navigator>
</NavigationContainer>
And my Drawer Component is just going to be a custom Drawer component:
const Drawer = ({ navigation }) => {
const Drawer = createDrawerNavigator();
return (
<Drawer.Navigator
drawerContent={(props) => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="Home" component={LandingScreens} />
</Drawer.Navigator>
);
};
My question is something like this possible? I was trying to tigger the navigation.openDrawer() from the tabPress but couldn't find the method. I am doing this right, or would I need some sort of custom bottomNav? Any help is much appreciated!
Thanks.
You can either use DrawerActions.openDrawer:
import { DrawerActions } from '#react-navigation/native'
<Tab.Screen
name="Menu"
component={Drawer}
listeners={({ navigation }) => ({
tabPress: (e) => {
e.preventDefault();
navigation.dispatch(DrawerActions.openDrawer())
},
})}
/>
A better solution is to nest the tabs inside the drawer so navigation.openDrawer() works.
https://reactnavigation.org/docs/nesting-navigators#navigator-specific-methods-are-available-in-the-navigators-nested-inside

Categories

Resources