I'm learning react native but I'm having difficulty with navigation, it's returning the error that navigation has not been initialized yet.
I looked for some tutorials, I tried some other ways, I went to the react native navigation documentation and, incredible as it may seem, it's the same as in the documentation... not even the GPT chat haha it didn't help me.
Can someone with experience in react native give me a light?
app.tsx:
import { NavigationContainer } from '#react-navigation/native';
import { createAppContainer } from 'react-navigation';
import StackNavigator from './app/index/navigator';
const AppContainer = createAppContainer(StackNavigator);
const App = () => {
return (
<NavigationContainer>
<AppContainer />
</NavigationContainer>
);
}
export default App;
navigator.tsx?
import { createStackNavigator } from 'react-navigation-stack';
import Index from '.';
import AddNewGrocery from '../components/addNewGrocery'
const StackNavigator = createStackNavigator({
home: { screen: Index, navigationOptions: { headerShown: false } },
addNewGrocery: { screen: AddNewGrocery, navigationOptions: { headerShown: false } },
});
export default StackNavigator;
index.tsx:
const Index = () => {
return (
<View style={styles.container}>
<Text style={styles.title}>Gestão de Compras</Text>
<LastFiveGrocery />
<MonthAverageSpend />
<TotalSpend />
<AddButton />
<StatusBar
translucent={false}
backgroundColor={'rgba(43, 43, 43, 1)'}
barStyle='light-content' />
</View>
);
}
AddButton.tsx:
import React from 'react';
import { StyleSheet, View, TouchableOpacity } from 'react-native';
import { Ionicons } from '#expo/vector-icons';
import { useNavigation } from '#react-navigation/native';
const AddButton = () => {
const navigation = useNavigation();
const handleAddButtonPress = () => {
navigation.navigate('addNewGrocery' as never);
}
return (
<TouchableOpacity style={styles.addButtonContainer} onPress={handleAddButtonPress}>
<View style={styles.addButton}>
<Ionicons name="ios-add" size={36} color="white" />
</View>
</TouchableOpacity>
);
}
I already tried to use it this way:
AddButton:
const { navigate } = useNavigation<StackNavigationProp<ParamListBase>>();
const handleAddButtonPress = () => {
navigate('addNewGrocery');
}
I've also tried using it this way:
navigator:
const StackNavigator = createAppContainer(createStackNavigator({
Home: { screen: Index },
addNewGrocery: AddNewGrocery,
}));
app.tsx:
import StackNavigator from './app/index/navigator';
const App = () => {
return (
<StackNavigator />
);
}
export default App;
You are using 2 different navigation library in simultaneously:
#react-navigation
react-navigation
Remove react-navigation and refactor the App.js file as below:
import { NavigationContainer } from '#react-navigation/native';
import StackNavigator from './app/index/navigator';
const App = () => {
return (
<NavigationContainer>
<StackNavigator />
</NavigationContainer>
);
}
export default App
StackNavigator should be implemented as per documentation -
https://reactnavigation.org/docs/stack-navigator/#api-definition
Related
StackRoutes.tsx Component (used in App.tsx)
export const StackRoutes = () => {
const Stack = createNativeStackNavigator()
return (
<NavigationContainer>
<Stack.Navigator initialRouteName={Path.introductionScreen}>
<Stack.Screen
name={Path.onBoardingChooseAliasScreen}
options={Options.onBoardingChooseAliasScreen}
component={OnBoardingChooseAlias}
/>
</Stack.Navigator>
</NavigationContainer>
)
}
Options.tsx component (being used in StackRoutes.tsx)
import React from 'react'
import { NativeStackNavigationOptions } from '#react-navigation/native-stack'
import { CustomBackButton } from './CustomBackButton'
const onBoardingChooseAliasScreen: NativeStackNavigationOptions = {
headerLeft: () => { return <CustomBackButton />}
}
export default {
onBoardingChooseAliasScreen,
}
CustomBackButton.tsx component (being used in Options.tsx)
import React from 'react'
import styled from 'styled-components/native'
import SVGimg from 'src/shared/images/greenMarker.svg'
export const CustomBackButton: React.FC<any> = ({ navigation }) => {
return (
<Wrapper onPress={() => navigation.goBack()}>
<SVGimg />
</Wrapper>
)
}
const Wrapper = styled.Pressable``
The CustomBackButton gets displayed as desired, but the goBack() function doesnt work. If i use default back button it works, so i know there is a stack to fall back on.
How do I make the goBack function work?
It seems like CustomBackButton does not have access to navigation
can you try with useNavigation hook
import React from 'react'
import styled from 'styled-components/native'
import SVGimg from 'src/shared/images/greenMarker.svg'
import { useNavigation } from '#react-navigation/native';
export const CustomBackButton: React.FC<any> = () => {
const navigation = useNavigation()
return (
<Wrapper onPress={() => navigation.goBack()}>
<SVGimg />
</Wrapper>
)
}
const Wrapper = styled.Pressable``
I have used createStackNavigator for Normal navigation and createMaterialTopTabNavigator for Tab navigation
Nested navigation is acting strangely. I have a StackNavigator in App.tsx that contains ProfileHome.tsx. The ProfileHome.tsx contains Tab navigations that have four screens. I wanted to navigate to the PastWorkDetail.tsx screen which is a part of the StackNavigator from PastWork.tsx (Tab)
Whenever I navigate from PastWork (Tab) to PastWorkDetail, the screen PastWorkDetail appears and automatically redirects to the previous screen, which is PastWork (Tab)
App.tsx
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import React, { useState } from "react";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { RootStackParamList } from "./navigation/types";
import LoginHome from "./screens/login/LoginHome";
import SplashScreen from "./screens/login/SplashScreen";
import SocialMediaSelectPage from "./screens/preference/SocialMediaSelectPage";
import PastWorkDetail from "./screens/profile/PastWorkDetail";
import ProfileHome from "./screens/profile/ProfileHome";
const RootStack = createStackNavigator<RootStackParamList>();
const App = () => {
return (
<SafeAreaProvider>
<NavigationContainer>
<RootStack.Navigator
initialRouteName="LoginHome">
<RootStack.Screen name="LoginHome" component={LoginHome} />
<RootStack.Screen name="SocialMediaSelectPage" component={SocialMediaSelectPage}/>
<RootStack.Screen name="ProfileHome" component={ProfileHome} />
<RootStack.Screen name="PastWorkDetail" component={PastWorkDetail} />
<RootStack.Screen name="Test" component={Test} />
</RootStack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
);
};
export default App;
ProfileHome.tsx
import { createMaterialTopTabNavigator } from "#react-navigation/material-top-tabs";
import React from "react";
import { View } from "react-native";
import HeaderProfile from "../../components/header/HeaderProfile";
import PastWork from "./PastWork";
import Preferences from "./Preferences";
import Profile from "./Profile";
import TopTabBar from "./shared/TopTabBar";
import Stats from "./Stats";
interface TabItem {
name: string;
component: React.ComponentType<any>;
}
const tabs: TabItem[] = [
{ name: "Profile", component: Profile },
{ name: "Stats", component: Stats },
{ name: "Preferences", component: Preferences },
{ name: "Pastwork", component: PastWork },
];
const ProfileHome = () => {
const Tab = createMaterialTopTabNavigator();
return (
<View style={styles.container}>
<Tab.Navigator backBehavior="history" nitialRouteName="Profile" tabBar={(props) => <TopTabBar {...props} />}>
{
// Populating tabs
tabs.map((item: TabItem, index: number) => {
return (
<Tab.Screenkey={index} name={item.name} component={item.component}
options={{
tabBarLabel: item.name,
}}
/>
);
})
}
</Tab.Navigator>
</View>
);
};
export default ProfileHome;
PastWork.tsx
import { useNavigation } from "#react-navigation/native";
import React from "react";
import { Image, ImageSourcePropType, StyleSheet, View } from "react-native";
const images = [
require("../../assets/images/pastWork1.jpeg"),
require("../../assets/images/pastWork2.png")
];
const PastWork = () => {
const navigation = useNavigation();
const onPress = () => {
navigation.navigate("PastWorkDetail");
};
return (
<View style={styles.container}>
<View style={{ width: Utils.getWidth(45) }}>
{
images.map((item, index) => {
return (
<ImageView key={index} source={item} onPress={onPress} />
);
})
}
</View>
</View>
);
};
export default PastWork;
PastWorkDetail.tsx
import React from "react";
import { StyleSheet, View } from "react-native";
import Header from "../../components/header/Header";
const PastWorkDetail = () => {
return (
<View style={styles.container}>
<Header name="Pastwork Info" />
</View>
);
};
export default PastWorkDetail;
I want to push a screen but its not working:
TypeError: navigation.push is not a function. (In 'navigation.push('Restaurants', {
name: params
})', 'navigation.push' is undefined)
Explore.tsx
import { useNavigation } from '#react-navigation/core';
import { NativeStackScreenProps } from '#react-navigation/native-stack';
import React from 'react';
import { StyleSheet, Text, View, Pressable, ScrollView } from 'react-native';
import { RootStackParams } from '../../App';
import Card from '../components/Card';
type PropNav = NativeStackScreenProps<RootStackParams, 'Explore'>;
const Explore = ({ navigation }: PropNav) => {
const handleNavigate = (params: string) => {
navigation.push('Restaurants', { name: params });
};
return (
<View style={{marginTop: 200}}>
<ScrollView>
<Card name="Zum Profil" onPress={(params) => handleNavigate(params)} />
</ScrollView>
</View>
)
};
export default Explore;
App.tsx
import { StatusBar } from 'expo-status-bar';
import { useState } from 'react';
import { FlatList, StyleSheet, Text, View } from 'react-native';
import Explore from './src/screens/Explore';
import { NavigationContainer, NavigatorScreenParams } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import Profile from './src/screens/Profile';
import Restaurants from './src/screens/Restaurants';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import ProfileIcon from './src/icon/ProfileIcon';
export type RootStackParams = {
Explore: undefined;
Profile: undefined;
RestaurantsStack: NavigatorScreenParams<RestaurantTypesParms>;
Restaurants: {
name: string
}
}
const RootStack = createBottomTabNavigator<RootStackParams>();
export type RestaurantTypesParms = {
Restaurants: {
name: string
}
}
const RestaurantStack = createNativeStackNavigator<RestaurantTypesParms>();
const RestaurantScreen = () => {
return ( <RestaurantStack.Navigator>
<RestaurantStack.Screen name="Restaurants" component={Restaurants} />
</RestaurantStack.Navigator>)
};
export default function App() {
const [text, setText] = useState('');
return (
<NavigationContainer>
<RootStack.Navigator initialRouteName='Explore'
screenOptions={{
headerShown: false,
tabBarActiveTintColor: 'purple'
}}
>
<RootStack.Screen name="Explore" component={Explore}
options={{
tabBarIcon: ({ color, size }) => <ProfileIcon color={color} size={size} />,
tabBarLabel: "Explore"
}}
/>
<RootStack.Screen name="Profile" component={Profile} />
<RootStack.Screen name="RestaurantsStack" component={RestaurantScreen} />
</RootStack.Navigator>
</NavigationContainer>
);
}
But if I use navigation.navigate then it works....
........................................................................................................................................................................................................................................
The push method for the navigation prop is added additional for the StackNavigator. You can compare this with the official documentation.
The stack navigator adds the following methods to the navigation prop:
push
Pushes a new screen to top of the stack and navigate to it. The method accepts following arguments:
name - string - Name of the route to push onto the stack.
params - object - Screen params to pass to the destination route.
You are not using a Stack.Navigator. You need to install #react-navigation/native-stack and use a different navigator to make this work. I would suggest that you go through this documentation where a full working example is provided.
you can try this.
const handleNavigate = (params: string) => {
navigation.navigate('Restaurants', { name: params });
};
or
const handleNavigate = (params: string) => {
navigation.replace('Restaurants', { name: params });
};
or
const handleNavigate = (params: string) => {
navigation.navigate('RestaurantScreen', { name: params });
};
With react-navigation 4, I was able to import and use switchNavigator from "react-navigation" package.
import {
createAppContainer,
createSwitchNavigator,
createStackNavigator
} from "react-navigation";
import MainTabNavigator from "./MainTabNavigator";
import LoginScreen from "../screens/LoginScreen";
import AuthLoadingScreen from "../screens/AuthLoadingScreen";
export default createAppContainer(
createSwitchNavigator(
{
App: MainTabNavigator,
Auth: AuthLoadingScreen,
Login: createStackNavigator({ Login: LoginScreen })
},
{
initialRouteName: "Auth"
}
)
);
With react-navigation 5, I don't see the createSwitchNavigator in the package anymore. The documentation isn't helpful either. Is the use now not recommended? My use case is to show login screen before user is logged in and switch to the app after user logs in. React-navigation has given an example of authentication flow but is it possible to use switchNavigator - which seems much simpler.
The switchNavigator was removed because you can do the exact same stuff now with the help of rendering components conditionally.
import React from 'react';
import {useSelector} from "react-redux";
import {NavigationContainer} from "#react-navigation/native";
import { AuthNavigator, MyCustomNavigator } from "./MyCustomNavigator";
const AppNavigator = props => {
const isAuth = useSelector(state => !!state.auth.access_token);
return (
<NavigationContainer>
{ isAuth && <MyCustomNavigator/>}
{ !isAuth && <AuthNavigator/>}
</NavigationContainer>
);
};
export default AppNavigator;
The lines inside the NavigationContainer fully replace the old switch navigator.
I had also used SwitchNavigator of Navigator 4 then after migrating other pages to Navigator 5, i tried to move authentication part to Navigator 5. I could not achieve SwitchNavigator functionality using Navigator 5. Then decided to use "Compatibility layer" provided in Navigation API 5. https://reactnavigation.org/docs/5.x/compatibility
Hope below code will useful for you.
import { createStackNavigator } from '#react-navigation/stack'
import { NavigationContainer } from '#react-navigation/native';
import { createSwitchNavigator } from "#react-navigation/compat";
import { createCompatNavigatorFactory } from '#react-navigation/compat'
const AppStack = createCompatNavigatorFactory(createStackNavigator)(
{ screen: Home },
{headerMode:'none'}
);
const AuthStack = createCompatNavigatorFactory(createStackNavigator)({ screen:Login });
const SwitchNavigator= createSwitchNavigator(
{
Starter: AuthValidation,
App: AppStack,
Auth: AuthStack
},
{
initialRouteName:'Starter'
}
);
export default function App (){
return(
<NavigationContainer>
<SwitchNavigator/>
</NavigationContainer>
);
}
Here AuthValidation validate for token and depending on value it navigate to "Login" or "Home" Page
_checkAuthetication = async() =>{
const isUserAuthenticated= await AsyncStorage.getItem("isAuthenticated");
this.props.navigation.navigate(isUserAuthenticated ? 'App':'Auth');
}
Hey there is no switch navigator in react navigation 5, however you can do this or something on the same lines:
import React, { useEffect } from 'react'
import { StyleSheet, Text, View, ActivityIndicator } from 'react-native'
import { NavigationContainer } from "#react-navigation/native";
import BottomTabsNavigator from './BottomTabsNavigator'
import AccountNavigator from './AccountNavigator'
import firebase from '../api/config'
const SwitchNavigator = ({navigation}) => {
useEffect(() => {
firebase.auth().onAuthStateChanged(user => {
navigation.navigate(user ? "BottomTabsNavigator" : "AccountNavigator")
})
}, [])
return (
<View style={styles.container}>
<Text>Loading...</Text>
<ActivityIndicator size="large" color="#e9446a"></ActivityIndicator>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})
export default SwitchNavigator
and then a Stack Navigator :
import React from 'react'
import { createStackNavigator } from '#react-navigation/stack'
import BottomTabsNavigator from './BottomTabsNavigator'
import AccountNavigator from './AccountNavigator'
import SwitchNavigator from './SwitchNavigator'
import { NavigationContainer } from "#react-navigation/native";
const StackApp = createStackNavigator()
export default function Stack() {
return (
<NavigationContainer>
<StackApp.Navigator initialRouteName='Loading' headerMode='none'>
<StackApp.Screen name='Loading' component={SwitchNavigator} />
<StackApp.Screen name='AccountNavigator' component={AccountNavigator}/>
<StackApp.Screen name='BottomTabsNavigator' component={BottomTabsNavigator}/>
</StackApp.Navigator>
</NavigationContainer>
)
}
and then import the Stack navigator into your app.js file like this:
export default App = () => ( <Stack /> )
This is w.r.t to above query
[Then how could we later navigate from a "LoginScreen" (inside
AuthNavigator ) to "HomeScreen" (inside MyCustomNavigator )? – TalESid
Apr 7 at 8:33 ]
const AuthNavigator = () => {
return(
<AuthStack.Navigator>
<Stack.Screen
name="Login"
component={Login}
options={{ headerShown: false }}
/>
<Stack.Screen
name="SignUp"
component={SignUp}
options={{ headerShown: false }}
/>
</AuthStack.Navigator>
);
}
const MyCustomNavigator = () => {
return(
<AppStack.Navigator>
<Stack.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
<Stack.Screen
name="ListScreen"
component={ListScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Settings"
component={Settings}
options={{ headerShown: false }}
/>
</AppStack.Navigator>
);
}
const AppNavigator = (props) => {
const isAuth = useSelector((state) => !!state.auth.access_token);
return (
<NavigationContainer>
{isAuth && <MyCustomNavigator />}
{!isAuth && <AuthNavigator />}
</NavigationContainer>
);
};
export default AppNavigator;
There isnt a switch navigator in react-navigation v5 or v6. however, i found switch very easy, and i find stack very difficult to use, so i continue to use react-navigation v4.2.0 or 4.4.1, so i can continue using switch
Hi i 'm new to react native how to implement a drawer navigator in react native. Actually i'm following this doc
Updated:
code for home page is as follows
constructor(props){
super(props)
this.state= {
icon: null
}
}
render(){
return(
<Container>
<Header style={{backgroundColor:'pink'}} >
<Button
transparent
onPress= {() => this.props.navigation.navigate("DrawerOpen")}>
<Icon
style= {{color: '#ffffff', fontSize:25, paddingTop:0}}
name="bars"
/>
</Button>
</Header>
<Content>
</Content>
</Container>
);
}
}
also
index.js
import CourseListing from './CourseListing';
import SideBar from './SideBar/SideBar';
import {DrawerNavigator} from 'react-navigation';
import Profile from './Profile';
const MyHome =DrawerNavigator(
{
CourseListing: {screen: CourseListing},
Profile: {screen: Profile},
},
{
contentComponent: props => <SideBar {...props} />
}
);
I'm getting this error
In addition to the documentation which is great, I also recommend watching This video.
I would suggest creating a file called Router.js. It could look something like this:
import React from 'react';
import { DrawerNavigator } from 'react-navigation';
import Screens1 from ... // Import all your screens here
import Screens2 from ...
import Screens3 from ...
// The DrawerNavigator uses all the screens
export const MyDrawer = DrawerNavigator({
Screen1: { screen: Screen1 },
Screen2: { screen: Screen2 },
Screen3: { screen: Screen3 },
});
In your root (usually called App.js) make sure to import MyDrawer:
import React, { Component } from 'react';
import { MyDrawer } from '(correct path here)/Router.js';
export default class App extends Component {
render() {
return <MyDrawer />;
}
}
Now when the app starts Screen1 will be loaded. Each of the screens has a side menu because of the DrawerNavigator. To open the menu in any screen, use the following method:
_openMenu() {
this.props.navigation.navigate('DrawerOpen');
}
Hope this helps.
it's so, implement drawer such as stack-navgation
exmaple :
import { createDrawerNavigator } from 'react-navigation-drawer';
import {signIn,drawer} from 'scene'
const RouteConfigs = {
signIn
}
const DrawerNavigatorConfig = {
drawerPosition:'right',
drawerType:'front',
hideStatusBar:true,
contentComponent:drawer
}
export default createDrawerNavigator(RouteConfigs, DrawerNavigatorConfig);
the important part is contentComponent in DrawerNavigatorConfig. it's a view that shows in the drawer when it opens
import React, { Component } from "react";
import { Dimensions, StyleSheet, } from 'react-native';
import { createStackNavigator } from '#react-navigation/stack';
import { createDrawerNavigator } from '#react-navigation/drawer';
import color from '../../../constants/color'
import Attendance from '../../ExtraScreens/Attendance/Attendance'
import KIETDigitalDirectory from '../../ExtraScreens/KIETDigitalDirectory/KIETDigitalDirectory'
import KIETExtensions from '../../ExtraScreens/KIETExtensions/KIETExtensions'
import StudentRedressal from '../../ExtraScreens/StudentRedressal/StudentRedressal'
//
import Ticketing from '../../ExtraScreens/Ticketing/Ticketing'
import TicketingApply from '../../ExtraScreens/Ticketing/TicketingApply'
//
import Grievance from '../../ExtraScreens/EmployeeGrievance/Grievance'
import GrievanceApply from '../../ExtraScreens/EmployeeGrievance/GrievanceApply'
export default class Extra extends React.Component {
render() {
const Drawer = createDrawerNavigator();
return (
<Drawer.Navigator
drawerType="back"
// openByDefault
// overlayColor="transparent"
>
<Drawer.Screen name="KIET Extensions" component={KIETExtensions} />
<Drawer.Screen name="Grievance" component={GrievanceStack} />
<Drawer.Screen name="Ticketing" component={TicketingStack} />
<Drawer.Screen name="Student Redressal" component={StudentRedressal} />
<Drawer.Screen name="Attendance" component={Attendance} />
<Drawer.Screen name="KIET Digital Directory" component={KIETDigitalDirectory} />
</Drawer.Navigator>
)
}
}
const StackNavigator = createStackNavigator();
const GrievanceStack = (props) => (
<StackNavigator.Navigator
initialRouteName="Grievance"
mode="card"
headerMode="none"enter code here>
<StackNavigator.Screen name="Grievance" component={Grievance} />
<StackNavigator.Screen name="Grievance Apply" component={GrievanceApply} />
</StackNavigator.Navigator>
)
const TicketingStack = (props) => (
<StackNavigator.Navigator
initialRouteName="Ticketing"
mode="card"
headerMode="none"
>`enter code here`
<StackNavigator.Screen name="Ticketing" component={Ticketing} />
<StackNavigator.Screen name="Ticketing Apply" component={TicketingApply} />
</StackNavigator.Navigator>
)