nested navigation question - how to export BottomTabNavigator - react-native

I am stuck with a problem with my bottomTabNavigator that should load the main pages for the app (main, kowops, wallet, scan) which is nested in a stack navigator that handles the login / registration screens (login, register, forget password).
This is my main.js
import React, { Component } from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import Scan from './Scan';
import Kowops from './Kowops';
import Wallet from './Wallet';
export default class Main extends Component {
render() {
return (
<View style={styles.container}>
<View style={{alignItems: 'center'}}>
<Text style={styles.plainText} onPress={() => this.props.navigation.navigate('Register')}>
This is the main page, return to registration
</Text>
<View style={{height:5}}></View>
</View>
</View>
)
}
}
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Main" component={Main} />
<Tab.Screen name="Scan" component={Scan} />
<Tab.Screen name="Wallet" component={Wallet} />
<Tab.Screen name="Kowops" component={Kowops} />
</Tab.Navigator>
</NavigationContainer>
);
}
export function BottomNav() {
return (
<NavigationContainer>
<MyTabs />
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 2,
backgroundColor:'#ffffff',
padding: 10,
alignItems: 'stretch',
justifyContent: 'space-around'
},
logoContainer: {
height: 120,
padding: 10,
alignItems: 'center' ,
justifyContent: 'flex-end'
},
logo: {
height: 50,
width: 165
},
formContainer: {
flex:1,
alignItems: 'center' ,
justifyContent: 'center'
},
buttonContainer: {
padding: 10,
marginBottom: 20,
width: 250,
alignItems: 'center',
backgroundColor: '#c5e1a5'
},
inputTextField: {
alignItems: 'center',
justifyContent: 'space-between',
padding: 10,
height: 40,
width: 250,
marginBottom: 10,
fontSize: 16,
borderBottomWidth : 1.0,
},
plainText: {
fontSize: 16,
marginBottom: 5,
color: '#59616e',
textDecorationLine: 'underline',
},
});
And this is my app.js with the login stack navigator
/**
* Load navigation
* Check login state
* Navigate to register.js if no valid session is detected
* Navigate to home.je is a valid session is detected
*/
import 'react-native-gesture-handler';
import React from 'react';
import Register from './register';
import Login from './login';
import main from './main';
import ForgotPassword from './forgotPassword';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Register" screenOptions={{headerShown: false}}>
<Stack.Screen name="Register" component={Register} />
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="ForgotPassword" component={ForgotPassword} />
<Stack.Screen name="Main" component={main} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
Now my bottomnavigation doesn't show on the main page. Ai already tried to replace the default in main.js like this
export class Main extends Component
&
export default function BottomNav()
But then I get
a nasty error:
Error: Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, pass 'independent={true}' explicitely. Note that this will make the child navigators disconnected from the parent and you won't be able to navigate between them.
This error is located at:
in ForwardRef(BaseNavigationContainer) (at NavigationContainer.tsx:66)
in ThemeProvider (at NavigationContainer.tsx:65)
in ForwardRef(NavigationContainer) (at main.js:42)
in BottomNav (at SceneView.tsx:98)
in StaticContainer
in StaticContainer (at SceneView.tsx:89)
in EnsureSingleNavigator (at SceneView.tsx:88)
in SceneView (at useDescriptors.tsx:125)
in RCTView (at CardContainer.tsx:199)
in RCTView (at CardContainer.tsx:198)
in RCTView (at CardSheet.tsx:33)
in ForwardRef(CardSheet) (at Card.tsx:526)
in RCTView (at createAnimatedComponent.js:144)
in AnimatedComponent (at createAnimatedComponent.js:194)
in ForwardRef(AnimatedComponentWrapper) (at Card.tsx:508)
in PanGestureHandler (at GestureHandler.native.tsx:13)
in PanGestureHandler (at Card.tsx:502)
in RCTView (at createAnimatedComponent.js:144)
in AnimatedComponent (at createAnimatedComponent.js:194)
in ForwardRef(AnimatedComponentWrapper) (at Card.tsx:498)
in RCTView (at Card.tsx:492)
in Card (at CardContainer.tsx:164)
in CardContainer (at CardStack.tsx:497)
in RCTView (at Screens.tsx:70)
in MaybeScreen (at CardStack.tsx:490)
in RCTView (at Screens.tsx:48)
in MaybeScreenContainer (at CardStack.tsx:388)
in CardStack (at StackView.tsx:433)
in KeyboardManager (at StackView.tsx:431)
in RNCSafeAreaView (at src/index.tsx:28)
in SafeAreaProvider (at SafeAreaProviderCompat.tsx:42)
in SafeAreaProviderCompat (at StackView.tsx:428)
in RCTView (at StackView.tsx:427)
in StackView (at createStackNavigator.tsx:82)
in StackNavigator (at App.js:21)
in EnsureSingleNavigator (at BaseNavigationContainer.tsx:288)
in ForwardRef(BaseNavigationContainer) (at NavigationContainer.tsx:66)
in ThemeProvider (at NavigationContainer.tsx:65)
in ForwardRef(NavigationContainer) (at App.js:20)
in App (at renderApplication.js:45)
in RCTView (at AppContainer.js:109)
in RCTView (at AppContainer.js:135)
in AppContainer (at renderApplication.js:39)
BaseNavigationContainer
BaseNavigationContainer.tsx:114:12
renderWithHooks
ReactNativeRenderer-dev.js:10989:26
updateForwardRef
ReactNativeRenderer-dev.js:13060:34
invokeGuardedCallbackImpl
ReactNativeRenderer-dev.js:286:4
invokeGuardedCallback
ReactNativeRenderer-dev.js:497:2
beginWork$$1
ReactNativeRenderer-dev.js:22028:27
performUnitOfWork
ReactNativeRenderer-dev.js:20871:23
workLoopSync
ReactNativeRenderer-dev.js:20848:38
performSyncWorkOnRoot
ReactNativeRenderer-dev.js:20456:22
performSyncWorkOnRoot
[native code]:0
runWithPriority$argument_1
ReactNativeRenderer-dev.js:5703:31
unstable_runWithPriority
scheduler.development.js:818:23
flushSyncCallbackQueueImpl
ReactNativeRenderer-dev.js:5698:21
flushSyncCallbackQueue
ReactNativeRenderer-dev.js:5686:28
flushSync
ReactNativeRenderer-dev.js:20630:26
scheduleRefresh
ReactNativeRenderer-dev.js:6492:13
mountedRoots.forEach$argument_0
react-refresh-runtime.development.js:218:8
forEach
[native code]:0
performReactRefresh
react-refresh-runtime.development.js:210:4
Refresh.performReactRefresh
setUpReactRefresh.js:43:6
setTimeout$argument_0
require.js:627:10
_callTimer
JSTimers.js:135:14
callTimers
JSTimers.js:387:16
__callFunction
MessageQueue.js:425:19
__guard$argument_0
MessageQueue.js:112:6
__guard
MessageQueue.js:373:10
callFunctionReturnFlushedQueue
MessageQueue.js:111:4
callFunctionReturnFlushedQueue
[native code]:0
Does anyone have an idea on how to fix this?
Best,
Tim

change
function MyTabs() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Main" component={Main} />
<Tab.Screen name="Scan" component={Scan} />
<Tab.Screen name="Wallet" component={Wallet} />
<Tab.Screen name="Kowops" component={Kowops} />
</Tab.Navigator>
</NavigationContainer>
);
}
export function BottomNav() {
return (
<NavigationContainer>
<MyTabs />
</NavigationContainer>
);
}
to
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Main" component={Main} />
<Tab.Screen name="Scan" component={Scan} />
<Tab.Screen name="Wallet" component={Wallet} />
<Tab.Screen name="Kowops" component={Kowops} />
</Tab.Navigator>
);
}
export function BottomNav() {
return (
<MyTabs />
);
}
you are nesting NavigationContainer remove NavigationContainers as I mentioned.
Hope this helps!

Related

Maximum depth exceeded: how to define a stack for a tab?

I tried following React-Navigation tutorial to implement Stack Navigator Within a Tab Navigator in React Native application using expo.
I am trying to achieve the following
RootStack (Stack Navigator)
Home (Screen)
Login (Screen)
ConsumerApp (Tab Navigator)
SettingsStackScreen (Stack Navigator)
Settings (Screen)
Details (Screen)
BusinessApp
Orders (screen)
Even when following the tutorial and using the code defined there (as you can see from SettingsStackScreen) I am getting the following error printed over and over again. The BusinessApp works great, because it doesn't have Stack Navigators defined within it, only pure component screen.
ERROR Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
in PreventRemoveProvider (created by NavigationContent)
in NavigationContent
in Unknown (created by NativeStackNavigator)
in NativeStackNavigator (created by SettingsStackScreen)
in SettingsStackScreen (created by SceneView)
I tried creating the most minimal example possible, so I wasn't sure what else to change/try.
This is root stack navigator in App.js
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} options={{ headerShown: false }} />
<Stack.Screen name="Login" component={LoginScreen} options={{ title: t('Login-s') }}/>
<Stack.Screen name="ConsumerApp" component={ConsumerAppScreen} options={{headerShown: false}}/>
<Stack.Screen name="BusinessApp" component={BusinessAppScreen} options={{headerShown: false}}/>
</Stack.Navigator>
</NavigationContainer>
);
}
The ConsumerAppScreen:
const Tab = createBottomTabNavigator();
export const ConsumerAppScreen = () => {
const { t, i18n } = useTranslation();
function DetailsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Details!</Text>
</View>
);
}
function SettingsScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}
const SettingsStack = createNativeStackNavigator();
function SettingsStackScreen() {
return (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
<SettingsStack.Screen name="Details" component={DetailsScreen} />
</SettingsStack.Navigator>
);
}
return (
<Tab.Navigator
initialRouteName="Settings"
tabBar={(props) => <ConsumerTabBar {...props} />}
>
<Tab.Screen name="Settings" component={SettingsStackScreen} options={{ icon: require("../../assets/dashboard-icon.png"), title: t('Settings') }} />
</Tab.Navigator>
)
}
It's because the way you created ConsumerAppScreen is not correct. Screen components and StackNavigator declarations shouldn't be inside a react component.
(I think the tab bar should have more than one child, but I'm not sure about it.)
The correct implementation:
function DetailsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Details!</Text>
</View>
);
}
function SettingsScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}
const SettingsStack = createNativeStackNavigator();
function SettingsStackScreen() {
return (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
<SettingsStack.Screen name="Details" component={DetailsScreen} />
</SettingsStack.Navigator>
);
}
// tab navigation
const Tab = createBottomTabNavigator();
export const ConsumerAppScreen = () => {
const { t, i18n } = useTranslation();
return (
<Tab.Navigator
initialRouteName="Settings"
tabBar={(props) => <ConsumerTabBar {...props} />}
>
<Tab.Screen name="Settings" component={SettingsStackScreen} options={{ icon: require("../../assets/dashboard-icon.png"), title: t('Settings') }} />
</Tab.Navigator>
)
}

Undefined Is Not A Function (React Navigation Bottom Tab Navigator)

I am building bottom tabs navigator from react navigation v6 in react native mobile app but encountered an error.
ERROR TypeError: undefined is not a function
This error is located at:
in MaybeScreenContainer (created by BottomTabView)
in RNCSafeAreaProvider (created by SafeAreaProvider)
in SafeAreaProvider (created by SafeAreaInsetsContext)
in SafeAreaProviderCompat (created by BottomTabView)
in BottomTabView (created by BottomTabNavigator)
in PreventRemoveProvider (created by NavigationContent)
in NavigationContent
in Unknown (created by BottomTabNavigator)
in BottomTabNavigator (created by tabNavigation)
in EnsureSingleNavigator
in BaseNavigationContainer
in ThemeProvider
in NavigationContainerInner (created by tabNavigation)
in tabNavigation (created by App)
in RCTView (created by View)
in View (created by App)
in authState (created by App)
in App
in RCTView (created by View)
in View (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
in KFC(RootComponent), js engine: hermes
The Code Of Tab Navigator That I have written for tabs. I am using physical device for test:
import React from 'react';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import Home from '../views/Home';
import Auth from '../views/Auth';
import Bucket from '../views/Bucket';
import Menu from '../views/Menu';
import {NavigationContainer} from '#react-navigation/native';
const Tab = createBottomTabNavigator();
export default function tabNavigation() {
return (
<NavigationContainer>
<Tab.Navigator initialRouteName="home">
<Tab.Screen name="home" component={Home} />
<Tab.Screen name="auth" component={Auth} />
<Tab.Screen name="bucket" component={Bucket} />
<Tab.Screen name="menu" component={Menu} />
</Tab.Navigator>
</NavigationContainer>
);
}
Ran into the same error. Turns out, bottom tabs navigator also needs react-native-screens.
yarn add react-native-screens | npm install react-native-screens should do the trick. You may have to re-build or clear your cache as well.
Try to replace your screen one by one and you will find your trouble maker
import React from 'react';
import { View, Text } from 'react-native'
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
//import Home from '../views/Home';
//import Auth from '../views/Auth';
//import Bucket from '../views/Bucket';
//import Menu from '../views/Menu';
import {NavigationContainer} from '#react-navigation/native';
const Tab = createBottomTabNavigator();
function Dummy() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Dummy</Text>
</View>
);
}
export default function tabNavigation() {
return (
<NavigationContainer>
<Tab.Navigator initialRouteName="home">
<Tab.Screen name="home" component={Dummy} />
<Tab.Screen name="auth" component={Dummy} />
<Tab.Screen name="bucket" component={Dummy} />
<Tab.Screen name="menu" component={Dummy} />
</Tab.Navigator>
</NavigationContainer>
);
}

How to create a customized clickable and scrollable top tab navigation in react native?

I am using react navigation v6. What I want is a clickable and scrollable tabs in top tab navigator? In 3rd party Modules, there are many issues so that's why currently I am not using that.
import React from 'react'
import {StatusBar} from 'react-native'
import {NavigationContainer} from '#react-navigation/native'
import {GestureHandlerRootView} from 'react-native-gesture-handler'
import {createMaterialTopTabNavigator} from '#react-navigation/material-top-tabs'
import HomeScreen from './screens/HomeScreen'
import LivingRoom from './screens/LivingRoom'
import Fav from './screens/Fav'
import Settings from './screens/Settings'
const Tab = createMaterialTopTabNavigator()
const AppRoot = () => {
return (
<GestureHandlerRootView className="flex-1">
<StatusBar hidden />
<NavigationContainer>
<Tab.Navigator
screenOptions={{
tabBarScrollEnabled: true,
tabBarIndicator: () => null,
tabBarStyle: {
backgroundColor: '#000',
},
tabBarItemStyle: {
width: 'auto',
alignItems: 'flex-start',
},
tabBarLabelStyle: {
fontSize: 30,
fontFamily: 'Satoshi-Black',
color: '#fff',
textTransform: 'capitalize',
},
}}
sceneContainerStyle={{backgroundColor: '#000'}}>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Living Room" component={LivingRoom} />
<Tab.Screen name="Fav" component={Fav} />
<Tab.Screen name="Settings" component={Settings} />
</Tab.Navigator>
</NavigationContainer>
</GestureHandlerRootView>
)
}
export default AppRoot

React Native - Open Drawer not working when using Navigation.push()

I am working on a React Native Expo app where I have both Stack Navigation and Drawer Navigation.
I have nested Drawer Navigator inside my Stack Navigator in app.js. When I click on Drawer hamburger menu, it opens the drawer from the right hand side. It was working fine on all the screens without any issue.
The problem occured when I decided to use this.props.navigation.push("Payment") to push to payment screen.
OpenDrawer() function is not passed as part of a prop when using navigation.push() whereas its working fine when using navigation.navigate().
OpenDrawer() function works in the payment screen when I navigate to that screen using below statement
this.props.navigation.navigate("Payment");
OpenDrawer() function throws function not found error when I navigate to that screen using below statement
this.props.navigation.push("Payment");
Below is my app.js where i nested drawer inside stack navigator. Can someone please advise how to resolve the issue. Thanks !!!
app.js
import React from "react";
import {
Dimensions,
ScrollView,
Button,
View,
SafeAreaView,
} from "react-native";
import { createStackNavigator } from "#react-navigation/stack";
import {
createDrawerNavigator,
DrawerContentScrollView,
} from "#react-navigation/drawer";
import {
NavigationContainer,
useNavigation,
DrawerItem,
} from "#react-navigation/native";
import Landingzone from "./components/Landingzone";
import LandingPage from "./components/LandingPage";
import Summary from "./components/Summary";
import Payment from "./components/Payment";
import { TouchableOpacity } from "react-native-gesture-handler";
import { Icon, Text } from "react-native-elements";
const myFont = Platform.OS === "ios" ? "Arial" : "sans-serif";
let myFontSize = 15;
const SCREEN_WIDTH = Dimensions.get("window").width;
if (SCREEN_WIDTH > 300 && SCREEN_WIDTH <= 360) {
myFontSize = 10;
} else if (SCREEN_WIDTH > 300 && SCREEN_WIDTH <= 415) {
}
export default function App() {
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const DrawerNavigator = () => (
<Drawer.Navigator
drawerPosition="right"
drawerContentOptions={{
labelStyle: {
color: "white",
fontFamily: myFont,
fontSize: 16,
},
}}
drawerStyle={{
backgroundColor: "#343a40",
flex: 1,
flexDirection: "column",
}}
drawerContent={(props) => (
<DrawerContentScrollView
contentContainerStyle={{
flex: 1,
flexDirection: "column",
}}
>
<View
style={{
flex: 0.15,
}}
>
<Icon
reverse
name="user-circle-o"
type="font-awesome"
color="#517fa4"
containerStyle={{
backgroundColor: "green",
left: 115,
}}
/>
<Text>SaimugaTutorials#gmail.com</Text>
</View>
<View
style={{
flex: 0.1,
justifyContent: "center",
}}
>
<Text>Enroll</Text>
</View>
</DrawerContentScrollView>
)}
>
<Drawer.Screen
name="Summary"
component={Summary}
options={{ headerShown: false }}
/>
<Drawer.Screen
name="Payment"
component={Payment}
options={{ headerShown: false }}
/>
</Drawer.Navigator>
);
const StackNavigator = () => (
<Stack.Navigator initialRouteName="Welcome">
<Stack.Screen
name="Welcome"
component={LandingPage}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Payment"
component={Payment}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Summary"
component={DrawerNavigator}
options={{ headerShown: false, gestureEnabled: false }}
/>
</Stack.Navigator>
);
return (
<NavigationContainer>
<StackNavigator />
</NavigationContainer>
);
}

Invariant Violation: Element type is invalid: expected a string - react native

I got this error message but I don't know!
Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of `BackgroundDecorator`.
This error is located at:
in BackgroundDecorator (at BottomNavigation.js:130)
in RCTView (at View.js:71)
in View (at BottomNavigation.js:129)
in BottomNavigation (at App.js:80)
in RCTView (at View.js:71)
in View (at App.js:68)
in App (created by AwakeInDevApp)
in RCTView (at View.js:71)
in View (created by AwakeInDevApp)
in AwakeInDevApp (at registerRootComponent.js:35)
in RootErrorBoundary (at registerRootComponent.js:34)
in ExpoRootComponent (at renderApplication.js:35)
in RCTView (at View.js:71)
in View (at AppContainer.js:102)
in RCTView (at View.js:71)
in View (at AppContainer.js:122)
in AppContainer (at renderApplication.js:34)
- node_modules/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js:5103:6 in createFiberFromElement
- node_modules/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js:7379:8 in reconcileSingleElement
- ... 28 more stack frames from framework internals
my code is:
import React from 'react'
import { View, StyleSheet, Image } from 'react-native'
import BottomNavigation, {
IconTab,
Badge
} from 'react-native-material-bottom-navigation'
import Icon from '#expo/vector-icons/MaterialCommunityIcons'
export default class App extends React.Component {
state = {
activeTab: 'games'
}
tabs = [
{
key: 'games',
label: 'Games',
barColor: '#388E3C',
pressColor: 'rgba(255, 255, 255, 0.16)',
icon: 'gamepad-variant'
},
{
key: 'movies-tv',
label: 'Movies & TV',
barColor: '#00695C',
pressColor: 'rgba(255, 255, 255, 0.16)',
icon: 'movie'
},
{
key: 'music',
label: 'Music',
barColor: '#6A1B9A',
pressColor: 'rgba(255, 255, 255, 0.16)',
icon: 'music-note'
},
{
key: 'books',
label: 'Books',
barColor: '#1565C0',
pressColor: 'rgba(255, 255, 255, 0.16)',
icon: 'book'
}
]
state = {
activeTab: this.tabs[0].key
}
renderIcon = icon => ({ isActive }) => (
<Icon size={24} color="white" name={icon} />
)
renderTab = ({ tab, isActive }) => (
<IconTab
isActive={isActive}
showBadge={tab.key === 'movies-tv'}
renderBadge={() => <Badge>2</Badge>}
key={tab.key}
label={tab.label}
renderIcon={this.renderIcon(tab.icon)}
/>
)
render() {
return (
<View style={{ flex: 1, backgroundColor: 'white' }}>
<View style={{ flex: 1, justifyContent: 'flex-end' }}>
<Image
source={require('./cut.png')}
style={{
resizeMode: 'contain',
width: 412,
bottom: -120,
opacity: 0.5
}}
/>
</View>
<BottomNavigation
tabs={this.tabs}
activeTab={this.state.activeTab}
onTabPress={newTab => this.setState({ activeTab: newTab.key })}
renderTab={this.renderTab}
useLayoutAnimation
/>
</View>
)
}
}
in some cases change the way the component is created is enough
import React, { Component } from 'react'
export default class ComponentName extends Component {
}