Nested Tab Bar in stack with modal screen (React Navigation v5) - javascript

I am using react-navigation v5 right now.I have Tab navigator with 3 screens 'Home', 'Discover', 'Profile'. I need to make navigation that way i could present modal screen complitely on top of tab navigator.In docs i didn't found how to do it from Tab navigator. So i deside to nest Tab navigator inside Stack navigator. And now i have tons of issues i need to resolve:
How i can show header for each tab in Tab navigator nested inside stack.
Show modal screen from view inside 'Home'.
Since i am using typescript before v5 i was using v4 with
NavigationInjectedProps. I could access fron nested component inside 'Home' with no problems, but now i having undefined props.navigation
MainNavigator.tsx
import HomeScreen from './Home/HomeScreen';
import DiscoverScreen from './Discover/DiscoverScreen';
import ProfileScreen from './profile/ProfileScreen';
import StreamsTabScreen from './Discover/tabview/tabScreens/StreamsTabScreen';
import { Image, Platform, View } from 'react-native';
import React from 'react';
import images from 'assets/images'
import DeviceInfo from 'react-native-device-info';
import VideoPlayer from '../../library/ui/videoPlayer/VideoPlayer';
import { createStackNavigator } from '#react-navigation/stack';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
export type TabNavigationProp = {
Home: undefined; //
Discover: undefined; // Should be here all undefined ????
Profile: undefined; //
}
export type StacknavigationProp = {
TabNavigator: undefined; // Same here ???
ModalPlayer: undefined; //
}
const Tab = createBottomTabNavigator();
const Stack = createStackNavigator();
const TabNavigator = () => {
return (
<Tab.Navigator>
<Tab.Screen name='Home' component={HomeScreen} />
<Tab.Screen name='Discover' component={DiscoverScreen} />
<Tab.Screen name='Profile' component={ProfileScreen} />
</Tab.Navigator>
);
};
const MainStackNavigator = () => {
return (
<Stack.Navigator mode='modal'>
<Stack.Screen name='TabNavigator' component={TabNavigator} options={{ headerShown: false }} />
<Stack.Screen name='ModalPlayer' component={VideoPlayer} />
</Stack.Navigator>
);
}
export default MainStackNavigator;
HomeScreen.tsx
import { View, Text, StyleSheet, ScrollView } from "react-native";
import React from "react";
import StreamsScreen from '../../streamsScreen/StreamsScreen';
import VideoplayerScreen from '../../videoplayer/VideoplayerScreen';
import { CompositeNavigationProp } from '#react-navigation/native';
import { BottomTabNavigationProp } from '#react-navigation/bottom-tabs';
import { StackNavigationProp } from '#react-navigation/stack';
import { TabNavigationProp, StacknavigationProp } from "../MainNavigator";
export type HomeScreenNavigationProps = CompositeNavigationProp<
BottomTabNavigationProp<TabNavigationProp, 'Home'>,
StackNavigationProp<StacknavigationProp>
>; // made props type from docs guide...
export default class HomeScreen extends React.Component<HomeScreenNavigationProps> {
render() {
console.log(this.props.navigate); //navigate is undefined...
return (
<View style={styles.container}>
<ScrollView style={styles.scrollView}>
<View style={{ paddingBottom: 24 }}>
<StreamsScreen navigate={this.props.navigation} /> //props.navigation does not exist
<View style={styles.separator} ></View>
<VideoplayerScreen />
</View>
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
scrollView: {
flex: 1,
backgroundColor: '#0C2B33',
paddingBottom: 20,
},
separator: {
height: 1,
backgroundColor: '#3D908E'
}
});
StreamsScreen.tsx
import { View, Text, StyleSheet, Image, ActivityIndicator } from 'react-native';
import MainViewItem from '../../library/ui/MainViewItem';
import { NavigationState, SceneRendererProps, TabBar, SceneMap } from 'react-native-tab-view';
import images from 'assets/images';
import { Props as IndicatorProps } from '../../library/indicator/TabBarIndicator';
import { fetchStreamsPending, fetchStreamsRefresh } from '../../redux/actions/streamActions';
import { connect } from "react-redux";
import { RootState } from "src/redux/reducers";
import numberFormatter from "../../library/utils/numberFormatter";
import palette from 'assets/palette';
import getLanguage from '../../library/utils/isoLanguages';
import {
StreamsState,
StreamsPendingState,
StreamsErrorState,
StreamsPageOffsetState,
Stream,
StreamsRefreshState
} from '../../redux/store/types';
import { TouchableOpacity } from 'react-native-gesture-handler';
import { HomeScreenNavigationProps } from '../main/Home/HomeScreen';
interface StreamsProps {
fetchStreamsPending: typeof fetchStreamsPending;
fetchStreamsRefresh: typeof fetchStreamsRefresh;
streams: StreamsState
pending: StreamsPendingState;
error: StreamsErrorState;
pageOffset: StreamsPageOffsetState;
refresh: StreamsRefreshState;
}
type State = NavigationState<{
key: string;
}>;
type Route = {
key: string;
};
class StreamsScreen extends React.Component<StreamsProps & HomeScreenNavigationProps> { // HomeScreenNavigationProps not sure what right prop type i need here ....
...
_onPressCard = () => {
this.props.navigation.navigate('ModalPlayer'); //Property 'navigation' does not exist on type ...
this.props.navigate('ModalPlayer'); //undefined here
}
...
UPADE: I fixed the problem with navigation, i didnt implement all logic for navigation with typescript...
should do something like this:
export type TabParamList = {
Home: undefined;
Discover: undefined;
Profile: undefined;
}
export type MainStackParamList = {
TabNavigator: undefined;
Stack2Nav: undefined;
ModalPlayer: undefined;
}
export type MainStackParamList2 = {
Home: undefined;
Discover: undefined;
Profile: undefined;
}
const Tab = createBottomTabNavigator<TabParamList>();
const RootStack = createStackNavigator<MainStackParamList>();
const TabNavigator = () => {
return (
<Tab.Navigator>
<Tab.Screen name='Home' component={HomeScreen} />
<Tab.Screen name='Discover' component={DiscoverScreen} />
<Tab.Screen name='Profile' component={ProfileScreen} />
</Tab.Navigator>
);
};
const MainStackNavigator = () => {
return (
<RootStack.Navigator mode='modal'>
<RootStack.Screen name='Tab' component={Tab} options={{ headerShown: false }} />
<RootStack.Screen name='ModalPlayer' component={VideoPlayer} />
</RootStack.Navigator>
);
}
in HomeScreen.tsx :
export type HomeScreenNavigationProp = CompositeNavigationProp<
BottomTabNavigationProp<TabParamList, 'Home'>,
StackNavigationProp<MainStackParamList>
>;
type Props = {
navigation: HomeScreenNavigationProp;
};
export default class HomeScreen extends React.Component<Props> {
render() {
return (
<View style={styles.container}>
<ScrollView style={styles.scrollView}>
<View style={{ paddingBottom: 24 }}>
<StreamsScreen navigation={this.props.navigation} />
<View style={styles.separator} ></View>
<VideoplayerScreen />
</View>
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
scrollView: {
flex: 1,
backgroundColor: '#0C2B33',
paddingBottom: 20,
},
separator: {
height: 1,
backgroundColor: '#3D908E'
}
});
Now what issue left is modal screen showing header even after setup mode='modal' in root stack navigator, even tho i copy pasted code from demo in docs.

Looks like the demo gif and code didn't show same behavior, i just added
{ headerShown: false } in my modal screen options:
<RootStack.Screen
name='ModalPlayer'
component={VideoPlayer}
options={{ headerShown: false }}
/>

Related

'Hamburger' icon isn't opening or closing the component - React Navigation V6

Would anyone be able to give me help regarding React Navigation with Expo? The issue is with the drawer component where the 'Hamburger' icon isn't opening or closing the component when a user presses the icon. However, it does open/close on a default swipe gesture from React Navigation. Please see below for my code:
Router:
import React from 'react';
import { NavigationContainer, DrawerActions } from '#react-navigation/native';
import { createDrawerNavigator } from '#react-navigation/drawer';
import { IconButton } from 'react-native-paper'
import i18n from '../i18n/i18n';
//Theme
import Theme from '../theme/theme'
//Components
import Menu from '../components/Menu'
//Import Interfaces
import { RootDrawerParamList } from '../utils/typescript/type.d';
import { IProps } from '../utils/typescript/props.d';
//Import Screens
import Screen1 from '../screens/Screen1';
import Screen2 from '../screens/Screen2';
import SettingsScreen from '../screens/Settings';
const Drawer = createDrawerNavigator<RootDrawerParamList>();
export default class Router extends React.Component<IProps, any> {
constructor(props: IProps) {
super(props);
}
render() {
return (
<NavigationContainer>
<Drawer.Navigator
initialRouteName='Screen1'
drawerContent={(props: any) => <Menu {...props} />}
screenOptions={({
swipeEnabled: true
})}>
<Drawer.Screen
name="Screen1"
component={Screen1}
initialParams={{ i18n: i18n, Theme: Theme }}
options={({route, navigation} : any) => ({
headerRight: () => (<IconButton icon="cog" size={24} color={Theme.colors.text} onPress={() => navigation.navigate('Settings')} />),
route: {route},
navigation: {navigation}
})}
/>
<Drawer.Screen
name="Settings"
component={SettingsScreen}
initialParams={{ i18n: i18n, Theme: Theme }}
options={({route, navigation} : any) => ({
headerTitle: i18n.t('settings', 'Settings'),
headerLeft: () => (<IconButton icon="arrow-left" color={Theme.colors.text} size={24} onPress={() => navigation.goBack()} />),
route: {route},
navigation: {navigation}
})}
/>
<Drawer.Screen
name="Screen2"
component={Screen2}
initialParams={{ i18n: i18n, Theme: Theme }}
options={({route, navigation} : any) => ({
route: {route},
navigation: {navigation}
})}
/>
</Drawer.Navigator>
</NavigationContainer>
);
}
}
Menu
import React from 'react';
import { FlatList, StyleSheet, View } from 'react-native';
import { List, Title } from 'react-native-paper';
import { getDefaultHeaderHeight } from '#react-navigation/elements';
import { DrawerItem } from '#react-navigation/drawer';
import { useSafeAreaFrame, useSafeAreaInsets } from 'react-native-safe-area-context';
//Import Interfaces
import { IListItem } from '../utils/typescript/types.d';
import { IPropsMenu } from '../utils/typescript/props.d';
import { IStateMenu } from '../utils/typescript/state.d';
//A function is used to pass the header height, using hooks.
function withHeightHook(Component: any){
return function WrappedComponent(props: IPropsMenu) {
/*
Returns the frame of the nearest provider. This can be used as an alternative to the Dimensions module.
*/
const frame = useSafeAreaFrame();
/*
Returns the safe area insets of the nearest provider. This allows manipulating the inset values from JavaScript. Note that insets are not updated synchronously so it might cause a slight delay for example when rotating the screen.
*/
const insets = useSafeAreaInsets();
return <Component {...props} headerHeight={getDefaultHeaderHeight(frame, false, insets.top)} />
}
}
class Menu extends React.Component<IPropsMenu, IStateMenu> {
constructor(props: IPropsMenu) {
super(props);
this.state = {
menu: [
{
name: 'screen1.name',
fallbackName: 'Screen 1',
icon: 'dice-multiple-outline',
iconFocused: 'dice-multiple',
onPress: this.props.navigation.navigate.bind(this, 'screen1')
},
{
name: 'screen2.name',
fallbackName: 'Screen 2',
icon: 'drama-masks',
iconFocused: 'drama-masks',
onPress: this.props.navigation.navigate.bind(this, 'screen2')
}
]
}
}
renderItem = (item : IListItem) => {
const { i18n } = this.props.state.routes[0].params;
return (
<DrawerItem
label={ i18n.t(item.name, item.fallbackName) }
onPress={ item.onPress ? item.onPress: () => {} }
icon={ ({ focused, color, size }) => <List.Icon color={color} style={[styles.icon, {width: size, height: size }]} icon={(focused ? item.iconFocused : item.icon) || ''} /> }
/>
);
};
render() {
const { headerHeight } = this.props;
const { menu } = this.state;
const { Theme } = this.props.state.routes[0].params;
return (
<View>
<View style={{
backgroundColor: Theme.colors.primary,
height: headerHeight ?? 0,
}}>
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-end',
}}>
<View style={{
flexDirection: 'row',
alignItems: 'center',
marginBottom: 5,
marginLeft: 5
}}>
<Title style={{ color: Theme.colors.text, marginLeft: 5 }}>
Title
</Title>
</View>
</View>
</View>
<FlatList
data={menu}
keyExtractor={item => item.name}
renderItem={({item}) => this.renderItem(item)}
/>
</View>
);
};
}
export default withHeightHook(Menu);
const styles = StyleSheet.create({
icon: {
alignSelf: 'center',
margin: 0,
padding: 0,
height:20
},
logo: {
width: 24,
height: 24,
marginHorizontal: 8,
alignSelf: 'center'
},
});
The solution to my issue was to encapsulate the drawer component in a native stack component. The 'Hamburger' icon works as expected, thanks for all the help and suggestions.
// Import Screens
import DrawRouter from './DrawRouter';
const Stack = createNativeStackNavigator<RootStackParamList>();
export default (): React.ReactElement => {
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="Main" component={DrawRouter} />
</Stack.Navigator>
</NavigationContainer>
);
};
Add the toogleDrawer() method to your onPress event on your Drawer.Navigator component:
onPress={()=> navigation.toggleDrawer()

How can i add a navigation drawer inside a stack navigator in an already existing project

Hello guys so I wanted to add a navigation DRAWER inside my main screen and I did not know how to nest it with the already existing stack navigator ,
this is my navigation component :
import React from "react";
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import ProductsOverviewScreen from "../screens/shop/ProductsOverviewScreen";
import ProductDetails from "../screens/shop/ProductDetailScreen";
import { HeaderButtons,Item } from "react-navigation-header-buttons";
import HeaderButton from '../components/UI/HeaderButton'
import CartScreen from "../screens/shop/CartScreen";
import OrdersScreen from "../screens/shop/OrdersScreen";
const RootNavigation=()=> {
const Stack = createStackNavigator();
const NavigationDrawerStructure = (props)=> {
//Structure for the navigatin Drawer
const toggleDrawer = () => {
//Props to open/close the drawer
props.navigationProps.toggleDrawer();
};
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={()=> toggleDrawer()}>
{/*Donute Button Image */}
<Image
source={{uri: 'https://raw.githubusercontent.com/AboutReact/sampleresource/master/drawerWhite.png'}}
style={{ width: 25, height: 25, marginLeft: 5 }}
/>
</TouchableOpacity>
</View>
);
}
const screenOptions ={
headerShown:true,
headerStyle: {
backgroundColor: 'white',},
headerTintColor: 'aqua',
headerTitleStyle: {
fontWeight: 'bold',
},
};
return(
<NavigationContainer>
<Stack.Navigator initialRouteName='ProductsOverview' screenOptions={screenOptions}>
<Stack.Screen name='ProductsOverview' component={ProductsOverviewScreen} options={({navigation,route})=>({title:'All Products',headerTitleStyle:{fontFamily:'open-sans-bold'},
headerRight:()=>( <HeaderButtons HeaderButtonComponent={HeaderButton}><Item title ='Cart' iconName='md-cart' onPress={()=>{navigation.navigate('CartScreen')}}/></HeaderButtons>)})}/>
<Stack.Screen name='ProductsDetail' component={ProductDetails} options={({route})=>({title:route.params.productTitle,headerTitleStyle:{fontFamily:'open-sans-bold'}})} />
<Stack.Screen name='CartScreen' component={CartScreen} options={{title:'Cart Items', headerTitleStyle:{fontFamily:'open-sans-bold'}}} />
<Stack.Screen name='OrdersScreen' component={OrdersScreen} options={{title:'Orders '}}/>
</Stack.Navigator>
</NavigationContainer>
)
}
export default RootNavigation;
and this is my app.js
import { StatusBar } from 'expo-status-bar';
import { StyleSheet } from 'react-native';
import {createStore , combineReducers} from 'redux';
import { Provider} from 'react-redux';
import AppLoading from 'expo-app-loading';
import * as Font from 'expo-font';
import productsReducer from './store/reducers/products';
import {composeWithDevTools} from 'redux-devtools-extension'
import RootNavigation from './navigation/ShopNavigation';
import cartReducer from './store/reducers/cart'
import { useState } from 'react';
import ordersReducer from './store/reducers/orders'
const rootReducer=combineReducers({
products: productsReducer,
cart: cartReducer,
orders:ordersReducer,
});
const store = createStore(rootReducer,composeWithDevTools());
const fetchFonts=()=>{
return Font.loadAsync({
'open-sans': require('./assets/fonts/OpenSans-Regular.ttf'),
'open-sans-bold': require('./assets/fonts/OpenSans-Bold.ttf')
})
}
export default function App() {
const [fontLoaded,setfontLoaded]= useState(false);
if (!fontLoaded) {
return (
<AppLoading
startAsync={fetchFonts}
onFinish={()=>setfontLoaded(true)}
onError={console.warn}
/>
);
}
return (
<Provider store={store}>
<RootNavigation />
</Provider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
can you give me an idea how to nest them together I tried using the docs but still full of errors
and Thanks
Drawer Navigator must be a parent to both Stack and Tab navigators. With that knowledge, let we refactor our code as below:
import React from "react";
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import ProductsOverviewScreen from "../screens/shop/ProductsOverviewScreen";
import ProductDetails from "../screens/shop/ProductDetailScreen";
import { HeaderButtons, Item } from "react-navigation-header-buttons";
import HeaderButton from "../components/UI/HeaderButton";
import CartScreen from "../screens/shop/CartScreen";
import OrdersScreen from "../screens/shop/OrdersScreen";
import { createDrawerNavigator } from "#react-navigation/drawer";
const RootNavigation = () => {
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const AppStack = () => (
<Stack.Navigator
initialRouteName="ProductsOverview"
screenOptions={screenOptions}
>
<Stack.Screen
name="ProductsOverview"
component={ProductsOverviewScreen}
options={({ navigation, route }) => ({
title: "All Products",
headerTitleStyle: { fontFamily: "open-sans-bold" },
headerRight: () => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Cart"
iconName="md-cart"
onPress={() => {
navigation.navigate("CartScreen");
}}
/>
</HeaderButtons>
),
})}
/>
<Stack.Screen
name="ProductsDetail"
component={ProductDetails}
options={({ route }) => ({
title: route.params.productTitle,
headerTitleStyle: { fontFamily: "open-sans-bold" },
})}
/>
<Stack.Screen
name="CartScreen"
component={CartScreen}
options={{
title: "Cart Items",
headerTitleStyle: { fontFamily: "open-sans-bold" },
}}
/>
<Stack.Screen
name="OrdersScreen"
component={OrdersScreen}
options={{ title: "Orders " }}
/>
</Stack.Navigator>
);
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="MainStack" component={AppStack} />
</Drawer.Navigator>
</NavigationContainer>
);
};
export default RootNavigation;
I omitted component code below as can't access drawer.
const NavigationDrawerStructure = (props)=> {
//Structure for the navigatin Drawer
const toggleDrawer = () => {
//Props to open/close the drawer
props.navigationProps.toggleDrawer();
};
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={()=> toggleDrawer()}>
{/*Donute Button Image */}
<Image
source={{uri: 'https://raw.githubusercontent.com/AboutReact/sampleresource/master/drawerWhite.png'}}
style={{ width: 25, height: 25, marginLeft: 5 }}
/>
</TouchableOpacity>
</View>
);
}
Here a minified version of working implementation
https://snack.expo.dev/#emmbyiringiro/69dc5b

Error: Couldn't find any screens for the navigator. Have you defined any screens as its children?

I am trying to make dynamic tab.screen.
my code is like this:
import React from 'react';
import { Text, View, TouchableOpacity, Modal } from 'react-native';
import AsyncStorage from '#react-native-community/async-storage';
import Icon from 'react-native-vector-icons/FontAwesome5';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import Home from '../mainscreen/GeneralScreen';
import Core from '../mainscreen/CoreScreen';
import Docs from '../mainscreen/GeneralScreen';
import ESS from '../mainscreen/CoreScreen';
import General from '../mainscreen/GeneralScreen';
import HR from '../mainscreen/CoreScreen';
import Payroll from '../mainscreen/GeneralScreen';
import Server from '../mainscreen/CoreScreen';
const Tab = createBottomTabNavigator();
const tabcomponents = {
"Home" : Home,
"Core" : Core,
"Docs" : Docs,
"ESS" : ESS,
"General" : General,
"HR" : HR,
"Payroll" : Payroll,
"Server" : Server
};
class TabNavigator extends React.Component {
constructor() {
super();
this.state = {
dashboardtab:[],
}
this.tabnavigatorasync();
}
tabnavigatorasync = async () => {
try {
const dashboardtab = await AsyncStorage.getItem('dashboardtab');
const dashboardtabParse = JSON.parse(dashboardtab);
this.setState({dashboardtab: dashboardtabParse});
} catch (error) {
}
}
render(){
const tabnavigatorRender = this.state.dashboardtab.map((item, index) => {
const tabcomponentsrender = tabcomponents[item.admintab.label];
return <Tab.Screen name={item.admintab.label} component={tabcomponentsrender} key={index}/>
});
return(
<Tab.Navigator>
{tabnavigatorRender}
</Tab.Navigator>
)
}
}
export default TabNavigator;
the result appears an error like this:
Error: Couldn't find any screens for the navigator. Have you defined any screens as its children?
is there something wrong with the code i made?
As the error states you are not having any screens inside the TabNavigator.
When the component is mounted the array is empty and the data is loaded later.
So you can fix this like below
render(){
const tabnavigatorRender = this.state.dashboardtab.map((item, index) => {
const tabcomponentsrender = tabcomponents[item.admintab.label];
return <Tab.Screen name={item.admintab.label} component={tabcomponentsrender} key={index}/>
});
// Add this to return null or you can also show <ActivityIndicator/>
if(this.state.dashboardtab.length===0)
return null;
return(
<Tab.Navigator>
{tabnavigatorRender}
</Tab.Navigator>
)
}
Also call the tabnavigatorasync from componentDidMount instead of calling it from the constructor.
componentDidMount(){
this.tabnavigatorasync();
}
<NavigationContainer>
<Tab.Navigator
screenOptions={{
headerShown: false,
tabBarActiveTintColor: '#A968EE',
tabBarStyle: {
position: 'absolute',
backgroundColor: 'black',
},
}}>
{data?.map((val, index) => (
<Tab.Screen
key={index}
name={val?.Name}
options={{
tabBarLabel: val?.Name,
tabBarIcon: () => (
<Image
style={{
height: 20,
width: 20,
}}
source={val?.ImageSource}
/>
),
}}
component={val?.Component}
/>
))}
</Tab.Navigator>
</NavigationContainer>

How to go to another screen in top tab navigation in react native

I want to go out of top tab navigation but it unable to navigate. It's giving error The action 'NAVIGATE' with payload {"name":"LoginPage"} was not handled by any navigator.
Do you have a screen named 'LoginPage'?
If you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator
I use nesting navigation also but not work. My Screens are below
Top tab navigation screen
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createMaterialTopTabNavigator } from '#react-navigation/material-top-tabs';
import {widthPercentageToDP as wp, heightPercentageToDP as hp} from 'react-native-responsive-screen';
import ProfileData from './profiledata';
import ProfileLikeData from './profilelikedata';
import Fontisto from 'react-native-vector-icons/Fontisto';
const Tab = createMaterialTopTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color }) => {
let iconName;
let size;
if (route.name === 'Data') {
iconName = focused
? 'nav-icon-grid'
: 'nav-icon-grid';
size = focused
? 25
: 25;
} else if (route.name === 'Like') {
iconName = focused ? 'heart' : 'heart';
size = focused
? 20
: 20;
}
return <Fontisto name={iconName} size={size} color={color} />;
},
})}
tabBarOptions={{
activeTintColor: '#d40786',
inactiveTintColor: 'white',
showIcon:true,
showLabel:false,
indicatorStyle: {
width: 0, height: 0, elevation: 0,
},
tabStyle: { width: wp('52%'),borderRightWidth:1,borderColor:'white' },
style: { backgroundColor:'trasparent',borderTopWidth:0.5,borderColor:'white',paddingBottom:5 },
}}
>
<Tab.Screen name="Data" component={ProfileData} />
<Tab.Screen name="Like" component={ProfileLikeData} />
</Tab.Navigator>
</NavigationContainer>
);
}
profiledata.js
import React from 'react';
import { View, StyleSheet, Text,ImageBackground,TouchableOpacity,Image } from 'react-native';
import { FlatGrid } from 'react-native-super-grid';
import {widthPercentageToDP as wp, heightPercentageToDP as hp} from 'react-native-responsive-screen';
import { RFPercentage, RFValue } from "react-native-responsive-fontsize";
import Toast from 'react-native-simple-toast';
export default class ProfileData extends React.Component {
constructor(props) {
super(props);
this.state = {
videos:[],
loginid:'',
paused:true,
};
}
static navigationOptions = {
headerShown: false,
};
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<FlatGrid
data={this.state.videos}
spacing={0}
renderItem={({ item }) => (
<TouchableOpacity onPress={()=>navigate('LoginPage')} style={{flex:1}}>
// some data
</TouchableOpacity>
)}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex:1,
// paddingHorizontal:wp('2%'),
backgroundColor:'black',
height: hp('100%'),
},
});
You should create another stack that has your login screen or add the login screen in the tab navigator.
for the first do something like this in your app.js
import { createStackNavigator } from '#react-navigation/stack';
import LoginScreen from './LoginScreen'; //Just import the login screen
const AuthStack = createStackNavigator();
const AuthStackScreen = () => (
<AuthStack.Navigator>
<AuthStack.Screen
name="LoginPage"
component={LoginScreen}
/>
</AuthStack.Navigator>
);
//Then in your profiledata.js;
<TouchableOpacity onPress={()=>navigate('LoginPage')} style={{flex:1}}>
// some data
</TouchableOpacity>
And for the second option just add the login screen in your tab navigator;
<Tab.Screen name="Data" component={ProfileData} />
<Tab.Screen name="Like" component={ProfileLikeData} />
<Tab.Screen name="LoginPage" component={LoginScreen} /> //Don't forget to import it

Splash screen using react navigation

I have created a loading screen and a Registartion screen. I would like that after 2 second my loading screen goes which basically is splash screen changes to registration screen using settimeout , but it's showing: undefined is not an object(evaluating
'_this.props')
App works perfectly till the loading screen when the set time evoke the navigation.natvigate(reg)
it throw the error
App.js
import React,{Component, useState} from "react";
import { StyleSheet, Text, View } from "react-native";
import { AppLoading } from 'expo';
import * as Font from 'expo-font';
import Registrationscreen from './screen/Registrationscreen';
import Loadingscreen from './screen/Loadingscreen';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
function HomeScreen() {
return (
<Loadingscreen/>
);
}
function Registration() {
return (
<Registrationscreen/>
);
}
const Stack = createStackNavigator();
const getFonts = () => Font.loadAsync({
'light':require('./assets/font/font.ttf')
});
function App() {
const [fontsLoaded, setFontsLoaded] = useState(false);
if(fontsLoaded){
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="home" screenOptions={{
headerShown: false
}}>
<Stack.Screen name="home" component={HomeScreen}></Stack.Screen>
<Stack.Screen name="reg" component={Registration}></Stack.Screen>
</Stack.Navigator>
</NavigationContainer>
);
} else{
return (
<AppLoading
startAsync={getFonts}
onFinish={()=> setFontsLoaded(true)}
/>
)
}
}
export default App;
LoadingScreen js
import React, { Component, useState } from 'react';
import {View, Image, Text , StyleSheet, Animated} from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { NavigationActions } from "react-navigation";
import Logo from '../assets/Logo.png';
const switchtoAuth = () =>{
this.props.navigation.navigate("reg");
};
class Loadingscreen extends Component {
state = {
LogoAnime: new Animated.Value(0),
LogoText: new Animated.Value(0),
loadingSpinner: false,
};
componentDidMount() {
const {LogoAnime, LogoText} = this.state;
Animated.parallel([
Animated.spring(LogoAnime, {
toValue: 1,
tension: 20,
friction: 1,
duration: 2000,
}).start(),
Animated.timing(LogoText, {
toValue: 1,
duration: 1,
useNativeDriver: true
}),
]).start(() => {
this.setState({
loadingSpinner: true,
});
setTimeout(switchtoAuth,1200);
});
}
render () {
return (
<View style={styles.container}>
<Animated.View
style={{
opacity: this.state.LogoAnime,
top: this.state.LogoAnime.interpolate({
inputRange: [0, 1],
outputRange: [80, 0],
}),
}}>
<Image source={Logo} />
</Animated.View>
<Text style={styles.logotext}> AL HANA </Text>
</View>
);
}
}
export default Loadingscreen;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#036BDD',
justifyContent: 'center',
alignItems: 'center',
},
logotext:{
color: '#FFFFFF',
fontFamily: 'light',
fontSize: 26,
position: "absolute",
top: 700,
fontWeight: "bold",
letterSpacing: 3,
textAlign: "center",
},
});
since your LoadingScreen component is not a screen component it will not receive the navigation prop automatically, so you need to pass through props from HomeScreen
function HomeScreen({ navigation }) {
return (
<Loadingscreen navigation={navigation}/>
);
}
and in your LoadingScreen first you need to put the switchtoAuth inside the class component without the const and then call the navigation.navigate:
class Loadingscreen extends Component {
state = {
LogoAnime: new Animated.Value(0),
LogoText: new Animated.Value(0),
loadingSpinner: false,
};
switchtoAuth = () =>{
this.props.navigation.navigate("reg");
};
// the rest of your component
First of all, in your loading screen switchtoAuth() function is outside of the LoadingScreen class that should be inside LoadingScreen class.
Since you already made LoadingScreen as a screen just add it to NavigationContainer
<NavigationContainer>
<Stack.Navigator initialRouteName="home" screenOptions={{ headerShown: false}}>
<Stack.Screen name="Splash" component={LoadingScreen}></Stack.Screen> //add LoadingScreen here
<Stack.Screen name="home" component={HomeScreen}></Stack.Screen>
<Stack.Screen name="reg" component={Registration}></Stack.Screen>
</Stack.Navigator>
</NavigationContainer>
And inside LoadingScreen componentDidMount() do this
setTimeout(() => this.props.navigation.navigate("reg"), 2000);

Categories