Home > Software engineering >  How to navigate to a screen in parent navigation in React native
How to navigate to a screen in parent navigation in React native

Time:04-19

I am very new to React Navigation and am trying to implement the following functionality in react-native: I have a stack navigator as a parent and a bottom navigation bar as its child. From the home screen, when the user clicks the logout option, they should return to the Sign In screen which is a part of the parent navigation.

There are already a lot of questions regarding this, but I am not able to implement the previous solutions in my code.

Someone please help me out, the code is given below (This is an Expo managed project):

Navigation Components

import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import WelcomeScreen from "../screens/WelcomeScreen";
import Features from "../screens/Features";
import SignIn from "../screens/SignIn";
import Register from "../screens/Register";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { Icon } from "react-native-elements";
import Home from "../screens/Home";
import Reminders from "../screens/Reminders";
import Settings from "../screens/Settings";

const BottomNavbar = () => {
    const Tab = createBottomTabNavigator();
    return (
        <Tab.Navigator
            initialRouteName="Home"
            screenOptions={({ route }) => ({
                tabBarIcon: ({ focused }) => {
                    let iconName;
                    let rn = route.name;
                    if (rn === "Home") {
                        iconName = focused ? "home" : "home-outline";
                    } else if (rn === "Reminders") {
                        iconName = focused ? "list" : "list-outline";
                    } else if (rn === "Settings") {
                        iconName = focused ? "settings" : "settings-outline";
                    }
                    return (
                        <Icon
                            name={iconName}
                            size={25}
                            color="black"
                            type="ionicon"
                        />
                    );
                },
            })}
            showLabel
        >
            <Tab.Screen
                name="Home"
                component={Home}
                options={{ headerShown: false }}
            />
            <Tab.Screen
                name="Reminders"
                component={Reminders}
                options={{ headerShown: false }}
            />
            <Tab.Screen
                name="Settings"
                component={Settings}
                options={{ headerShown: false }}
            />
        </Tab.Navigator>
    );
};

const Navigator = () => {
    const Stack = createNativeStackNavigator();

    return (
        <NavigationContainer>
            <Stack.Navigator
                screenOptions={{ headerShown: false }}
                initialRouteName="Welcome"
            >
                <Stack.Screen name="Welcome" component={WelcomeScreen} />
                <Stack.Screen name="Features" component={Features} />
                <Stack.Screen name="SignIn" component={SignIn} />
                <Stack.Screen name="Register" component={Register} />
                <Stack.Screen name="BottomNavbar" component={BottomNavbar} />
            </Stack.Navigator>
        </NavigationContainer>
    );
};

export default Navigator;

Home Screen Components

import {
    View,
    Text,
    SafeAreaView,
    StyleSheet,
    TouchableOpacity,
    ScrollView,
} from "react-native";
import React from "react";
import { Header, Image, Icon } from "react-native-elements";
import { useFonts } from "expo-font";
import ServiceCard from "../components/ServiceCard";
import PetCard from "../components/PetCard";

const SignOut = ({ navigation }) => {
    return (
        <TouchableOpacity
            onPress={() => {
                navigation.navigate("SignIn");
            }}
        >
            <Icon name="logout" color="black" size={20} />
        </TouchableOpacity>
    );
};

const Home = () => {
    const [loaded, error] = useFonts({
        Montserrat: require("../assets/fonts/Montserrat-Regular.ttf"),
    });
    if (!loaded) {
        return null;
    }
    const url1 =
        "https://images.unsplash.com/photo-1530281700549-e82e7bf110d6?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=388&q=80";
    const url2 =
        "https://images.unsplash.com/photo-1560807707-8cc77767d783?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=435&q=80";
    const url3 =
        "https://images.unsplash.com/photo-1543466835-00a7907e9de1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=774&q=80";
    return (
        <View style={styles.screen}>
            <Header
                leftComponent={{
                    icon: "menu",
                    color: "black",
                }}
                rightComponent={<SignOut />}
                centerComponent={{
                    text: "PetPapa",
                    color: "black",
                    style: {
                        fontFamily: "Montserrat",
                        fontSize: 20,
                    },
                }}
                barStyle="dark-content"
                backgroundColor="white"
                containerStyle={styles.header}
            />
            <View style={styles.community}>
                <View style={styles.commOffer}>
                    <View>
                        <Text style={styles.commOfferTitle}>Join our</Text>
                        <Text style={styles.commOfferTitle}>
                            community today!
                        </Text>
                    </View>
                    <TouchableOpacity style={styles.btn}>
                        <Text style={styles.commOfferJoin}>Join Now</Text>
                    </TouchableOpacity>
                </View>
                <Image
                    source={{
                        uri: "https://imgur.com/nB4Xm1Z.png",
                    }}
                    style={styles.commDog}
                />
            </View>
            <View style={styles.listView}>
                <View style={styles.topText}>
                    <Text style={styles.title}>Services</Text>
                    <TouchableOpacity>
                        <Text style={styles.option}>See more</Text>
                    </TouchableOpacity>
                </View>
                <ServiceCard />
            </View>
            <View style={styles.listView}>
                <View style={styles.topText}>
                    <Text style={styles.title}>My Pets</Text>
                    <TouchableOpacity>
                        <Text style={styles.option}>See all</Text>
                    </TouchableOpacity>
                </View>
                <ScrollView
                    style={styles.petView}
                    horizontal={true}
                    showsHorizontalScrollIndicator={true}
                    persistentScrollbar={true}
                >
                    <PetCard name="Miles" Img={url1} />
                    <PetCard name="Jack" Img={url2} />
                    <PetCard name="Ellie" Img={url3} />
                </ScrollView>
            </View>
        </View>
    );
};

const styles = StyleSheet.create({
    screen: {
        height: "100%",
        backgroundColor: "white",
        alignItems: "center",
    },
    header: {
        backgroundColor: "white",
        height: 80,
    },
    community: {
        backgroundColor: "#1976D2",
        height: "15%",
        width: "80%",
        borderRadius: 20,
        marginTop: 50,
        flexDirection: "row",
        justifyContent: "space-around",
    },
    commDog: {
        marginTop: 10,
        marginRight: 15,
        height: 105,
        width: 75,
    },
    commOffer: {
        marginTop: 10,
        flexDirection: "column",
        justifyContent: "space-around",
    },
    commOfferTitle: {
        color: "white",
        fontFamily: "Montserrat",
        fontSize: 16,
    },
    btn: {
        backgroundColor: "#FFC107",
        width: "50%",
        borderRadius: 10,
    },
    commOfferJoin: {
        color: "white",
        margin: 5,
    },
    listView: {
        marginTop: 50,
        width: "80%",
    },
    topText: {
        flexDirection: "row",
        justifyContent: "space-between",
        alignItems: "center",
    },
    title: {
        fontFamily: "Montserrat",
        fontWeight: "600",
    },
    option: {
        fontFamily: "Montserrat",
        opacity: 0.4,
    },
    block: {
        backgroundColor: "#FF5677",
        width: 75,
        height: 100,
        justifyContent: "center",
        alignItems: "center",
        marginTop: 25,
        borderRadius: 20,
    },
    petView: {
        width: "100%",
        backgroundColor: "white",
        height: 250,
    },
});
export default Home;

My Directory Structure:

Directory Structure for project

CodePudding user response:

First you need to add navigation prop to Home screen component

const Home = ({navigation}) => {
    const [loaded, error] = useFonts({
        Montserrat: require("../assets/fonts/Montserrat-Regular.ttf"),
    });
   ...

then You need to pass navigation prop to the signout component

 <Header
    leftComponent={{
       icon: "menu",
       color: "black",
    }}
    rightComponent={<SignOut navigation={navigation} />}
    ...

You can also use useNavigation hook from react navigation

import { useNavigation } from '@react-navigation/native';

const SignOut = ({}) => {
    const navigation = useNavigation()
    return (
        <TouchableOpacity
            onPress={() => {
                navigation.navigate("SignIn");
            }}
        >
            <Icon name="logout" color="black" size={20} />
        </TouchableOpacity>
    );
};

If You want to create login flow then you should use Authentication flow which I think best prectice and recommended way

The problem in current flow if you logout and navigate to sign-in page once then if you navigate back from you app then as behaviour of stack navigation it just pop current screen and it will again navigate to home screen which is not what supposed to be correct.

You can learn it from react-navigation offical doc https://reactnavigation.org/docs/auth-flow/

if you want a video tutorial how to implement Authentication flow using redux(state management lib) then I have video tutorial you can learn this video -> https://youtu.be/cm1oJ7JmW6c

  • Related