Related
I have two navigators and the idea is to have the main navigation container to hold the general pages: Home, SignIn, SignUp, confirmEmail and NewPassword but once the user login in to Home I would like the navigation bar to display and have its own navigation routings.
Navigation.js:
<NavigationContainer>
<Stack.Navigator screenOptions={{headerShown: false}}>
{user ? (
<Stack.Screen name="HomeScreen" component={HomeScreen} />
) : (
<>
<Stack.Screen name="SignIn" component={SignInScreen} />
<Stack.Screen name="SignUp" component={SignUpScreen} />
<Stack.Screen name="ConfirmEmail" component={ConfirmEmailScreen} />
<Stack.Screen
name="ResetPassword"
component={ResetPasswordScreen}
/>
<Stack.Screen name="NewPassword" component={NewPasswordScreen} />
</>
)}
</Stack.Navigator>
</NavigationContainer>
Navbar.js
const Navbar = () => {
const tabOffsetValue = useRef(new Animated.Value(0)).current;
return (
// <NavigationContainer>
<Tab.Navigator
screenOptions={{
tabBarShowLabel: false,
headerShown: false,
// Floating Tab Bar...
tabBarStyle: {
backgroundColor: 'white',
position: 'absolute',
// Max Height...
borderRadius: 10,
// Shadow...
},
}}>
{
// Tab Screens....
// Tab ICons....
}
<Tab.Screen
name={'Home'}
component={HomeScreen}
options={{
tabBarIcon: ({focused}) => (
<View
style={{
// centring Tab Button...
position: 'absolute',
top: 20,
}}>
<Icon
name="home"
size={20}
color={focused ? 'red' : 'gray'}></Icon>
</View>
),
}}
listeners={({navigation, route}) => ({
// Onpress Update....
tabPress: e => {
Animated.spring(tabOffsetValue, {
toValue: 0,
useNativeDriver: true,
}).start();
},
})}>
</Tab.Screen>
HomeScreen.Js
const HomeScreen = () => {
const signOut = () => {
Auth.signOut();
};
return (
<View>
<Navbar/>
<Text style={{fontSize: 24, alignSelf: 'center'}}>Welcome to Flimpi</Text>
<Text
onPress={signOut}
style={{
width: '100%',
textAlign: 'center',
color: 'red',
marginTop: 'auto',
marginVertical: 20,
fontSize: 20
}}>
Sign Out!
</Text>
</View>
);
};
Expectedly I am getting the following error:
Require cycle: src/screens/HomeScreen/index.js -> src/components/Navbar/index.js -> src/components/Navbar/Navbar.js -> src/screens/HomeScreen/index.js
Require cycles are allowed, but can result in uninitialized values. Consider refactoring to remove the need for a cycle.
The Error makes sense but I just do not know how to structure the code
I am trying to navigate from Screen1 to Screen2. Screen1 is being rendered in my Home screen. So far I have tried using this.props.navigation.navigate as well as what you see currently implemented.
I have created a snack expo here that recreates the exact error as well as posted some code below.
Thank you for any insight at all, I appreciate it more than you know.
EDIT:: this needs to be ran on IOS and I am using react-native-navigation
App.js
/*passing props to home is from my overall project, I left it in incase it impacted the answer*/
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="HomeScreen" options={{ headerShown: false }}>
{(props) => (
<Home {...props}/>
)}
</Stack.Screen>
<Stack.Screen
name="Screen1"
component={Screen1}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Screen2"
component={Screen2}
options={{ headerShown: false }}
/>
</Stack.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<MyTabs/>
</NavigationContainer>
);
Screen1
export default class Screen1 extends React.Component {
renderList = (props, navigation) => {
return List.map((item, i) => {
return (
<View
key={List.name}
style={{
width: windowWidth,
height: scale(100),
paddingLeft: scale(10)
}}>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('Screen2')}
activeOpacity={0.7}>
<Text style={{fontSize: 20}}>{item.name}</Text>
</TouchableOpacity>
</View>
);
});
};
render() {
return (
<View style={{top: scale(50)}}>
<ScrollView style={{ height: windowHeight }}>
<this.renderList />
</ScrollView>
</View>
);
}
}
make use of hook useNavigation.
Home.js
const Home = (props) => {
const navigation = useNavigation();
return (
<View>
<Screen1 navigation={navigation} />
</View>
);
};
Screen1.js
export default class Screen2 extends React.Component {
renderList = (props) => {
return List.map((item, i) => {
return (
<View
key={List.name}
style={{
width: windowWidth,
height: scale(100),
paddingLeft: scale(10),
}}>
<TouchableOpacity onPress={() => {
props.navigation.navigate('Screen2')
}} activeOpacity={0.7}>
<Text style={{ fontSize: 20 }}>{item.name}</Text>
</TouchableOpacity>
</View>
);
});
};
render() {
const props= this.props;
return (
<View style={{ top: scale(50) }}>
<ScrollView style={{ height: windowHeight }}>
{ this.renderList (props) }
</ScrollView>
</View>
);
}
}
snack expo working code
In Screen 1
renderList = (props) => {
return List.map((item, i) => {
return (
<View
key={List.name}
style={{
width: windowWidth,
height: scale(100),
paddingLeft: scale(10)
}}>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('Screen2')}
activeOpacity={0.7}>
<Text style={{fontSize: 20}}>{item.name}</Text>
</TouchableOpacity>
</View>
);
});
in Home
const Home = (props) => {
return (
<View>
<Screen1 {...props}/>
</View>
);
}
And in App
<Tab.Navigator initialRouteName="Home">
<Tab.Screen name="Home" options={{ headerShown: false }} component={Home}/>
<Tab.Screen
name="Screen1"
component={Screen1}
options={{ headerShown: false }}
/>
<Tab.Screen
name="Screen2"
component={Screen2}
options={{ headerShown: false }}
/>
</Tab.Navigator>
And for me working perfectly (I take some capture but I'm not authorized yet, new user...)
Say me
You are not passing navigation props to Screen1. You can just pass navigation props to Screen1 like below code or it is better to make Screen1 as Initial Route instead of calling it as a component in Home screen.
Good method : Update following area in App.js like below
....
<Stack.Navigator initialRouteName="Screen1"> // made Screen1 as initial route
<Stack.Screen
name="Screen1"
component={Screen1}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Screen2"
component={Screen2}
options={{ headerShown: false }}
/>
</Stack.Navigator>
....
Method 2 : If you want Home Screen as Initial Route, then update following area in Home.js like below
....
const Home = (props) => {
return (
<View>
<Screen1 navigation={props.navigation}/> // navigation props passed to Screen1 component
</View>
);
}
....
My tab below code is a bottom-tab navigator code and I want to display it on every screen by rendering it on app.js as I did for the drawer navigator
(in simple words I want to call the bottom tab navigator on screen)
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
let user1=""
let data=""
export function DrwaerNav(props) {
if(props.route.params!=undefined){
console.log('props arent undefined')
user1=props.route.params.user.auth
data=props.route.params.user.auth
}
return (
<Drawer.Navigator initialRouteName="homeS" drawerContent={(props) => <DrawerContent props={props} data={user1}/>}
screenOptions={{
headerStyle:{
backgroundColor:'transparent',
},
headerTintColor:'black',
headerTitleStyle:{
fontWeight:'bold',
}
}}
>
<Drawer.Screen name="complaints" component={complaints}
options={{
title:'Home',
headerTitleAlign:'left',
headerRight:()=>(
<View style={{marginEnd:10,flexDirection:'row'}}>
<Text style={{paddingRight:15,paddingTop:13,fontWeight:"normal",}}>{user1.email}</Text>
<Avatar.Image
source={{ uri:base64.decode(user1.avatar)}}
size={40}
/>
{/* <Text>Email:{user1.email}</Text> */}
</View>
),
}}/>
<Drawer.Screen name="homeS" component={homeS} options={{
title:'Home',
headerTitleAlign:'left',
headerRight:()=>(
<View style={{marginEnd:10,flexDirection:'row'}}>
{/* <Text style={{paddingRight:15,paddingTop:13,fontWeight:"normal",fontSize:12,}}>{user1.email}</Text> */}
<TouchableOpacity
onPress={()=>{
props.navigation.navigate('Profile',data={data})
}
}>
<Avatar.Image
source={{ uri:base64.decode(user1.avatar)}}
size={40}
/>
</TouchableOpacity>
{/* <Text>Email:{user1.email}</Text> */}
</View>
),
}}/>
<Drawer.Screen name="Updates" component={updates}
options={{
title:'Home',
headerTitleAlign:'left',
headerRight:()=>(
<View style={{marginEnd:10,flexDirection:'row'}}>
<Text style={{paddingRight:15,paddingTop:13,fontWeight:"normal",}}>{user1.email}</Text>
<Avatar.Image
source={{ uri:base64.decode(user1.avatar)}}
size={40}
/>
{/* <Text>Email:{user1.email}</Text> */}
</View>
),
}}/>
<Drawer.Screen name="userComplaints" component={userComplaints}
options={{
title:'Home',
headerTitleAlign:'left',
headerRight:()=>(
<View style={{marginEnd:10,flexDirection:'row'}}>
<Text style={{paddingRight:15,paddingTop:13,fontWeight:"normal",}}>{user1.email}</Text>
<Avatar.Image
source={{ uri:base64.decode(user1.avatar)}}
size={40}
/>
{/* <Text>Email:{user1.email}</Text> */}
</View>
),
}}/>
<Drawer.Screen name="GuestReg" component={Guest}
options={{
title:'Home',
headerTitleAlign:'left',
headerRight:()=>(
<View style={{marginEnd:10,flexDirection:'row'}}>
<Text style={{paddingRight:15,paddingTop:13,fontWeight:"normal",}}>{user1.email}</Text>
<Avatar.Image
source={{ uri:base64.decode(user1.avatar)}}
size={40}
/>
{/* <Text>Email:{user1.email}</Text> */}
</View>
),
}}/>
<Drawer.Screen name="myGuests" component={myGuest}
options={{
title:'Home',
headerTitleAlign:'left',
headerRight:()=>(
<View style={{marginEnd:10,flexDirection:'row'}}>
<Text style={{paddingRight:15,paddingTop:13,fontWeight:"normal",}}>{user1.email}</Text>
<Avatar.Image
source={{ uri:base64.decode(user1.avatar)}}
size={40}
/>
{/* <Text>Email:{user1.email}</Text> */}
</View>
),
}}/>
<Drawer.Screen name="Updateguest" component={Updateguest}
options={{
title:'Home',
headerTitleAlign:'left',
headerRight:()=>(
<View style={{marginEnd:10,flexDirection:'row'}}>
<Text style={{paddingRight:15,paddingTop:13,fontWeight:"normal",}}>{user1.email}</Text>
<Avatar.Image
source={{ uri:base64.decode(user1.avatar)}}
size={40}
/>
{/* <Text>Email:{user1.email}</Text> */}
</View>
),
}}/>
<Drawer.Screen name="updateprofile" component={updateprofile}
options={{
title:'Update Profile',
headerTitleAlign:'left',
headerRight:()=>(
<View style={{marginEnd:10,flexDirection:'row'}}>
<Text style={{paddingRight:15,paddingTop:13,fontWeight:"normal",}}>{user1.email}</Text>
<Avatar.Image
source={{ uri:base64.decode(user1.avatar)}}
size={40}
/>
{/* <Text>Email:{user1.email}</Text> */}
</View>
),
}}/>
<Drawer.Screen name="Profile" component={Profile} />
</Drawer.Navigator>
);
}
My drawer navigator is working fine I want to add a bottom tab navigator its code is below:
const Tab = createMaterialBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator
activeColor="#e91e63"
barStyle={{ backgroundColor: 'tomato' }}
>
<Tab.Screen
name="homes"
component={DrwaerNav}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="home" color={color} size={26} />
),
}}
/>
<Tab.Screen
name="Updates"
component={updates}
options={{
tabBarLabel: 'Updates',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="bell" color={color} size={26} />
),
}}
/>
<Tab.Screen
name="Profile"
component={Profile}
options={{
tabBarLabel: 'Profile',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="account" color={color} size={26} />
),
}}
/>
</Tab.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Login" screenOptions={{
headerShown: false
}}>
{/* <Stack.Navigator initialRouteName="SignUp" headerShown="false"> */}
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="SignUp" component={SignUp} />
<Stack.Screen name="dashboard" component={DrwaerNav} />
</Stack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Please try below code with basic setup
import React from 'react'
import {NavigationContainer} from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack'
import { createDrawerNavigator } from '#react-navigation/drawer'
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs'
import { View, Text } from 'react-native'
const Stack = createStackNavigator()
const DrawerStack = createDrawerNavigator()
const BottomStack = createBottomTabNavigator()
// Drawer code
function AppDrawerStack() {
return (
<DrawerStack.Navigator drawerContent={props => <DrawerView {...props} />}>
<DrawerStack.Screen name='AppBottomStack' component={AppBottomStack} />
</DrawerStack.Navigator>
)
}
function DrawerView() {
return (
<View>
<Text>
Drawer View
</Text>
</View>
)
}
// Bottom Stack Part
function AppBottomStack() {
return (
<BottomStack.Navigator>
<BottomStack.Screen
name='BottomScreenOne'
component={BottomScreenOne}
/>
<BottomStack.Screen
name='BottomScreenTwo'
component={BottomScreenTwo}
/>
</BottomStack.Navigator>
)
}
function BottomScreenOne() {
return (
<View>
<Text>
BottomScreenOne
</Text>
</View>
)
}
function BottomScreenTwo() {
return (
<View>
<Text>
BottomScreenTwo
</Text>
</View>
)
}
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="AppDrawerStack" component={AppDrawerStack} />
</Stack.Navigator>
</NavigationContainer>
)
}
Please follow this GitHub repo here I have combined drawer, bottom and stack navigation
https://github.com/Gyanprakash73/DTSNavigator
Otherwise, Follow this below code
App.js
import 'react-native-gesture-handler';
import React from 'react';
import {createStackNavigator} from '#react-navigation/stack';
import {NavigationContainer} from '#react-navigation/native';
import DrawerNavigator from './src/navigation/DrawerNavigator';
const Stack = createStackNavigator();
const App = () => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="DrawerNavigator">
<Stack.Screen
name="DrawerNavigator"
component={DrawerNavigator}
options={{headerShown: false}}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
DrawerNavigator.js
import * as React from 'react';
import {View, StyleSheet, Image, Text, TouchableOpacity} from 'react-native';
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItemList,
} from '#react-navigation/drawer';
import MyRewardsStackNavigator from './stack-navigators/MyRewardsStackNavigator';
import LocationsStackNavigator from './stack-navigators/LocationsStackNavigator';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import BottomTabNavigator from './BottomTabNavigator';
const Drawer = createDrawerNavigator();
const DrawerNavigator = () => {
const DrawerHeaderContent = props => {
return (
<DrawerContentScrollView contentContainerStyle={{flex: 1}}>
<View
style={{
backgroundColor: '#4f4f4f',
height: 100,
justifyContent: 'center',
alignItems: 'center',
top: -5,
}}>
<Text style={{color: '#fff'}}>Home</Text>
</View>
<DrawerItemList {...props} />
</DrawerContentScrollView>
);
};
return (
<Drawer.Navigator
screenOptions={{
drawerStyle: {
backgroundColor: '#fff',
},
}}
drawerContent={DrawerHeaderContent}>
<Drawer.Screen
name={'BottomTabNavigator'}
component={BottomTabNavigator}
options={{
drawerLabel: 'Home Screen',
drawerIcon: ({focused, size, color}) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
),
}}
/>
<Drawer.Screen
name={'MyRewardsStackNavigator'}
component={MyRewardsStackNavigator}
options={{
drawerLabel: 'My Rewards Screen',
drawerIcon: ({focused, size, color}) => (
<MaterialCommunityIcons name="firewire" color={color} size={size} />
),
}}
/>
<Drawer.Screen
name={'LocationsStackNavigator'}
component={LocationsStackNavigator}
options={{
drawerLabel: 'Locations Screen',
drawerIcon: ({focused, size, color}) => (
<MaterialCommunityIcons
name="location-enter"
color={color}
size={size}
/>
),
}}
/>
</Drawer.Navigator>
);
};
const styles = StyleSheet.create({
headerLeft: {
marginLeft: 15,
},
headerTitle: {
color: 'white',
fontSize: 18,
fontWeight: '500',
},
headerRight: {
marginRight: 15,
},
// drawer content
drawerLabel: {
fontSize: 14,
},
drawerLabelFocused: {
fontSize: 14,
color: '#551E18',
fontWeight: '500',
},
drawerItem: {
height: 50,
justifyContent: 'center',
},
drawerItemFocused: {
backgroundColor: '#ba9490',
},
});
export default DrawerNavigator;
BottomTabNavigator.js
import * as React from 'react';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import {Text, StyleSheet, View} from 'react-native';
import HomeStackNavigator from './stack-navigators/HomeStackNavigator';
import BookStackNavigator from './stack-navigators/BookStackNavigator';
import ContactStackNavigator from './stack-navigators/ContactStackNavigator';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
const Tab = createBottomTabNavigator();
const BottomTabNavigator = () => {
return (
<Tab.Navigator initialRouteName="HomeScreen" screenOptions={{}}>
<Tab.Screen
name={'HomeStackNavigator'}
component={HomeStackNavigator}
options={{
tabBarLabel: 'Home Screen',
headerShown: false,
tabBarIcon: ({color, size}) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
),
}}
/>
<Tab.Screen
name={'BookStackNavigator'}
component={BookStackNavigator}
options={{
tabBarLabel: 'Book Screen',
headerShown: false,
tabBarIcon: ({color, size}) => (
<MaterialCommunityIcons
name="book-open-blank-variant"
color={color}
size={size}
/>
),
}}
/>
<Tab.Screen
name={'ContactStackNavigator'}
component={ContactStackNavigator}
options={{
tabBarLabel: 'Contact Screen',
headerShown: false,
tabBarIcon: ({color, size}) => (
<MaterialCommunityIcons name="contacts" color={color} size={size} />
),
}}
/>
</Tab.Navigator>
);
};
const styles = StyleSheet.create({
tabBarLabel: {
color: '#292929',
fontSize: 12,
},
tabContainer: {
height: 60,
},
});
export default BottomTabNavigator;
i have the exact same problem like on issue:
React Native header / bottom tabbar jumping on first app load
On every load the bottom bar jumps up and down for unknown reason. I wrapped the root app in SafeAreaProvider, i wrapped my screens in SafeAreaView and still the same thing happens.
Here is my code:
Root App:
const App = () => {
return (
<SafeAreaProvider>
<StatusBar backgroundColor="#01497C" />
<NavigationContainer>
<Stack.Navigator
initialRouteName="AuthLoadingScreen"
screenOptions={{headerShown: false}}>
<Stack.Screen
name="AuthLoadingScreen"
component={AuthLoadingScreen}
/>
<Stack.Screen name="Home" component={Tabs} />
<Stack.Screen name="QuizScreen" component={QuizScreen} />
<Stack.Screen name="QuizReviewScreen" component={QuizReviewScreen} />
<Stack.Screen name="QuizEndScreen" component={QuizEndScreen} />
</Stack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
);
};
Tabs:
const Tabs = () => {
const TabBarCustom = ({children, onPress}) => {
return (
<TouchableOpacity
style={{top: -10, justifyContent: 'center', alignItems: 'center'}}
onPress={onPress}
activeOpacity={1}>
<LinearGradient
style={{
width: 70,
height: 70,
borderRadius: 35,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 4,
},
shadowOpacity: 0.3,
shadowRadius: 4.65,
elevation: 8,
}}
colors={['#01497C', '#89C2D9']}>
{children}
</LinearGradient>
</TouchableOpacity>
);
};
return (
<Tab.Navigator
tabBarOptions={{
showLabel: false,
style: {
height: 60,
},
}}>
<Tab.Screen
name="Quizzes"
component={QuizzesScreen}
options={{
tabBarIcon: ({focused}) => (
<View style={{alignItems: 'center', justifyContent: 'center'}}>
<Ionicon
name="apps-outline"
color={focused ? '#89C2D9' : '#2A6F97'}
size={30}
/>
<Text
style={{color: focused ? '#89C2D9' : '#2A6F97', fontSize: 13}}>
Quizzes
</Text>
</View>
),
}}
/>
<Tab.Screen
name="Flashcards"
component={FlashCardsScreen}
options={{
tabBarIcon: ({focused}) => (
<View style={{alignItems: 'center', justifyContent: 'center'}}>
<Ionicon
name="copy-outline"
color={focused ? '#89C2D9' : '#2A6F97'}
size={30}
/>
<Text
style={{color: focused ? '#89C2D9' : '#2A6F97', fontSize: 13}}>
Flashcards
</Text>
</View>
),
}}
/>
<Tab.Screen
name="Import"
component={QuizzesScreen}
options={{
tabBarIcon: ({focused}) => (
<View style={{alignItems: 'center', justifyContent: 'center'}}>
<Icon
name="plus"
color={focused ? '#A9D6E5' : 'white'}
size={42}
/>
</View>
),
tabBarButton: props => <TabBarCustom {...props} />,
}}
/>
<Tab.Screen
name="Account"
component={QuizzesScreen}
options={{
tabBarIcon: ({focused}) => (
<View style={{alignItems: 'center', justifyContent: 'center'}}>
<Ionicon
name="person-outline"
color={focused ? '#89C2D9' : '#2A6F97'}
size={30}
/>
<Text
style={{color: focused ? '#89C2D9' : '#2A6F97', fontSize: 13}}>
Account
</Text>
</View>
),
}}
/>
<Tab.Screen
name="About"
component={QuizzesScreen}
options={{
tabBarIcon: ({focused}) => (
<View style={{alignItems: 'center', justifyContent: 'center'}}>
<Ionicon
name="search"
color={focused ? '#89C2D9' : '#2A6F97'}
size={30}
/>
<Text
style={{color: focused ? '#89C2D9' : '#2A6F97', fontSize: 13}}>
Search
</Text>
</View>
),
}}
/>
</Tab.Navigator>
);
};
The issue happens every time tabs get loaded.
I had the same issue, in my case I was using Custom StatusBar in different screens with different props. The issue was I wasn't using translucent prop in all screen StatusBar. Using translucent in all screen StatusBar fixed the problem. Give me a thumbs up if it solve your problem.
I use MaterialCommunityIcons for tab icons so,
I sove this issue with
useLayoutEffect(() => {
async function loadIcons() {
setIsLoading(true);
await MaterialCommunityIcons.loadFont();
setIsLoading(false);
}
loadIcons();
}, []);
if (isLoading) {
return <></>;
}
Why useLayouEffect?
The signature is identical to useEffect, but it fires synchronously after all DOM mutations. Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint. read more
I have a list of profiles on my Screen "NerdList" built using ListItems (react-native-element) and a Flatlist. When you click on a profile from the list, the app should navigate to the "Profile" screen and pass a test parameter with it.
NerdList Screen:
import React from "react";
import { withNavigation } from '#react-navigation/compat';
import { StyleSheet, FlatList} from "react-native";
import { ListItem } from "react-native-elements";
import nerdProfiles from '../constants/nerdProfiles';
import { Block, Text } from 'galio-framework';
import argonTheme from "../constants/Theme";
import { TouchableOpacity } from "react-native-gesture-handler";
class NerdList extends React.Component {
renderItem = ({item}) => (
<TouchableOpacity
onPress={() => this.props.navigation.navigate('Profile', {test: 'Hello'})}
>
<ListItem
title={
<Block>
<Text style={styles.names}>
{item.name}
</Text>
</Block>
}
subtitle={
<Block>
<Text style={styles.descriptions}>
{item.shortDescription}
</Text>
</Block>
}
leftAvatar={{ source: { uri: item.image } }}
bottomDivider
chevron
/>
</TouchableOpacity>
);
render() {
return (
<FlatList
data={nerdProfiles.bios}
renderItem={this.renderItem}
keyExtractor={item => item.id}
/>
);
};
};
export default withNavigation(NerdList);
The navigation alone works, but when I try to pass a parameter, I receive a TypeError: undefined is not an object (evaluating '_ref3.route').
Here is the code I am using to receive the route on the "Profile" screen:
const {test} = route.params;
Full Profile Screen Code:
import React from "react";
import {
StyleSheet,
Dimensions,
ScrollView,
Image,
ImageBackground,
Platform
} from "react-native";
import { Block, Text, theme } from "galio-framework";
import { Button } from "../components";
import { Images, argonTheme } from "../constants";
import { HeaderHeight } from "../constants/utils";
import { FlatList, TouchableWithoutFeedback } from "react-native-gesture-handler";
import nerdProfiles from "../constants/nerdProfiles";
import ArticleCard from "../components/ArticleCard";
import VideoCard from "../components/VideoCard";
const { width, height } = Dimensions.get("screen");
const thumbMeasure = (width - 48 - 32) / 3;
//keyExtractor = (item, index) => index.toString()
class Profile extends React.Component {
renderVideoItem = ({item}) => {
return(
<Block style={{ marginRight: theme.SIZES.BASE }}>
<TouchableWithoutFeedback>
<VideoCard
item={item}
imageStyle={{ width: "auto", height: 94 }}
style={{ width: width / 3.75}}
/>
</TouchableWithoutFeedback>
</Block>
);
};
renderArticleItem = ({item}) => {
return(
<Block style={{ marginRight: theme.SIZES.BASE }}>
<TouchableWithoutFeedback>
<ArticleCard
item={item}
imageStyle={{ width: "auto", height: 94 }}
style={{ width: width / 3.75}}
/>
</TouchableWithoutFeedback>
</Block>
);
};
render() {
const { params } = this.props.navigation.state;
const test= params ? params.test: null;
return (
<Block flex style={styles.profile}>
<Block flex>
<ImageBackground
source={Images.ProfileBackground}
style={styles.profileContainer}
imageStyle={styles.profileBackground}
>
<ScrollView
showsVerticalScrollIndicator={false}
style={{ width, marginTop: "25%" }}
>
<Block flex style={styles.profileCard}>
<Block middle style={styles.avatarContainer}>
<Image
source={{uri: nerdProfiles.bios[0].image}}
style={styles.avatar}
/>
</Block>
<Block style={styles.info}>
<Block
middle
row
space="evenly"
style={{ marginTop: 20, paddingBottom: 24 }}
>
<Button
small
style={{ backgroundColor: argonTheme.COLORS.DEFAULT }}
>
FOLLOW
</Button>
</Block>
<Block row space="between">
<Block middle>
<Text
size={18}
color="#525F7F"
style={{ marginBottom: 4, fontFamily: 'open-sans-bold' }}
>
2K
</Text>
<Text style={{ fontFamily: 'open-sans-regular' }} size={12} color={argonTheme.COLORS.TEXT}>Followers</Text>
</Block>
<Block middle>
<Text
color="#525F7F"
size={18}
style={{ marginBottom: 4, fontFamily: 'open-sans-bold' }}
>
10
</Text>
{test}
<Text style={{ fontFamily: 'open-sans-regular' }} size={12} color={argonTheme.COLORS.TEXT}>Content</Text>
</Block>
</Block>
</Block>
<Block flex>
<Block middle style={styles.nameInfo}>
<Text style={{ fontFamily: 'open-sans-regular' }} size={28} color="#32325D">
{test}
</Text>
<Text size={16} color="#32325D" style={{ marginTop: 10, fontFamily: 'open-sans-light' }}>
{nerdProfiles.bios[0].location}
</Text>
</Block>
<Block style={styles.categories}>
<Button small>Math</Button>
<Button small>Finance</Button>
<Button small>Physics</Button>
</Block>
<Block middle style={{ marginTop: 30, marginBottom: 16 }}>
<Block style={styles.divider} />
</Block>
<Block middle>
<Text
size={16}
color="#525F7F"
style={{ textAlign: "center", fontFamily: 'open-sans-regular' }}
>
{nerdProfiles.bios[0].longDescription}
</Text>
<Button
color="transparent"
textStyle={{
color: "#233DD2",
fontWeight: "500",
fontSize: 16,
fontFamily: 'open-sans-regular'
}}
>
Show more
</Button>
</Block>
<Block
row
style={{ paddingVertical: 14 }}
space="between"
>
<Text bold size={16} color="#525F7F" style={{ marginTop: 3 }}>
Video Appearances
</Text>
<Button
small
color="transparent"
textStyle={{ color: "#5E72E4", fontSize: 14 }}
>
View all
</Button>
</Block>
<Block style={{ marginHorizontal: theme.SIZES.BASE }}>
<FlatList
style={styles.flatlist}
keyExtractor={this.keyExtractor}
data={nerdProfiles.bios[0].videos}
renderItem={this.renderVideoItem}
horizontal={true}
showsHorizontalScrollIndicator={false}
/>
</Block>
<Block
row
style={{ paddingVertical: 14 }}
space="between"
>
<Text bold size={16} color="#525F7F" style={{ marginTop: 3 }}>
Articles Written
</Text>
<Button
small
color="transparent"
textStyle={{ color: "#5E72E4", fontSize: 14 }}
>
View all
</Button>
</Block>
<Block style={{ marginHorizontal: theme.SIZES.BASE }}>
<FlatList
style={styles.flatlist}
keyExtractor={this.keyExtractor}
data={nerdProfiles.bios[0].articles}
renderItem={this.renderArticleItem}
horizontal={true}
showsHorizontalScrollIndicator={false}
/>
</Block>
<Block
row
style={{ paddingVertical: 14 }}
space="between"
>
<Text bold size={16} color="#525F7F" style={{ marginTop: 3 }}>
Podcast Appearances
</Text>
<Button
small
color="transparent"
textStyle={{ color: "#5E72E4", fontSize: 14 }}
>
View all
</Button>
</Block>
<Block
row
style={{ paddingVertical: 14 }}
space="between"
>
<Text bold size={16} color="#525F7F" style={{ marginTop: 3 }}>
Live Appearances
</Text>
<Button
small
color="transparent"
textStyle={{ color: "#5E72E4", fontSize: 14 }}
>
View all
</Button>
</Block>
<Block
row
style={{ paddingVertical: 14 }}
space="between"
>
<Text bold size={16} color="#525F7F" style={{ marginTop: 3 }}>
Academic Work
</Text>
<Button
small
color="transparent"
textStyle={{ color: "#5E72E4", fontSize: 14 }}
>
View all
</Button>
</Block>
</Block>
</Block>
<Block style={{ marginBottom: 25 }}/>
</ScrollView>
</ImageBackground>
</Block>
</Block>
);
}
}
NerdList screen (first screen)
import React from "react";
import { Dimensions } from "react-native";
import { createStackNavigator } from "#react-navigation/stack";
import { createDrawerNavigator } from "#react-navigation/drawer";
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
// screens
import Feed from "../screens/Feed";
// import Onboarding from "../screens/Onboarding";
import Pro from "../screens/Pro";
import Profile from "../screens/Profile";
import Register from "../screens/Register";
import Elements from "../screens/Elements";
import Articles from "../screens/Articles";
import Search from "../screens/Search";
import Cart from "../screens/Cart";
import NerdList from "../screens/NerdList";
// settings
import SettingsScreen from "../screens/Settings";
import AgreementScreen from "../screens/Agreement";
import PrivacyScreen from "../screens/Privacy";
import AboutScreen from "../screens/About";
import NotificationsScreen from "../screens/Notifications";
// Notifications
import PersonalNotifications from "../screens/PersonalNotifications";
import SystemNotifications from "../screens/SystemNotifications";
// drawer
import CustomDrawerContent from "./Menu";
// header for screens
import { Icon, Header } from "../components";
import { argonTheme, tabs } from "../constants";
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
const { width } = Dimensions.get("screen");
export const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const Tab = createBottomTabNavigator();
function NotificationsStack() {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ color }) => {
let iconName;
if (route.name === "Personal") {
iconName = "user";
} else if (route.name === "System") {
iconName = "database";
} else if (route.name === "NerdList") {
iconName = "user"
}
// You can return any component that you like here!
return (
<Icon
name={iconName}
family="entypo"
size={22}
color={color}
style={{ marginTop: 10 }}
/>
);
}
})}
tabBarOptions={{
activeTintColor: argonTheme.COLORS.PRIMARY,
inactiveTintColor: "gray",
labelStyle: {
fontFamily: "open-sans-regular"
}
}}
>
<Tab.Screen name="Personal" component={PersonalNotifications} navigation />
<Tab.Screen name="System" component={SystemNotifications} />
<Tab.Screen name="NerdList" component={NerdList} />
</Tab.Navigator>
);
}
function BottomTabStack() {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ color }) => {
let iconName;
if (route.name === "Feed") {
iconName = "user";
} else if (route.name === "System") {
iconName = "database";
} else if (route.name === "NerdList") {
iconName = "user"
}
// You can return any component that you like here!
return (
<Icon
name={iconName}
family="entypo"
size={22}
color={color}
style={{ marginTop: 10 }}
/>
);
}
})}
tabBarOptions={{
activeTintColor: argonTheme.COLORS.PRIMARY,
inactiveTintColor: "gray",
labelStyle: {
fontFamily: "open-sans-regular"
}
}}
>
<Tab.Screen name="Feed" component={Feed} />
<Tab.Screen name="System" component={SystemNotifications} />
<Tab.Screen name="NerdList" component={NerdList} />
</Tab.Navigator>
);
}
function ElementsStack() {
return (
<Stack.Navigator mode="card" headerMode="screen">
<Stack.Screen
name="Elements"
component={Elements}
options={{
header: ({ navigation, scene }) => (
<Header title="Elements" navigation={navigation} scene={scene} />
),
cardStyle: { backgroundColor: "#F8F9FE" }
}}
/>
</Stack.Navigator>
);
}
function NerdListStack() {
return (
<Stack.Navigator mode="card" headerMode="screen">
<Stack.Screen
name="NerdList"
component={NerdList}
options={{
header: ({ navigation, scene }) => (
<Header title="NerdList" navigation={navigation} scene={scene} />
),
cardStyle: { backgroundColor: "#F8F9FE" }
}}
/>
<Stack.Screen
name="Profile"
component={Profile}
options={{
header: ({ navigation, scene }) => (
<Header
transparent
white
title="Profile"
navigation={navigation}
scene={scene}
back={true}
/>
),
cardStyle: { backgroundColor: "#FFFFFF" },
headerTransparent: true
}}
/>
</Stack.Navigator>
);
}
function SettingsStack() {
return (
<Stack.Navigator mode="card" headerMode="screen">
<Stack.Screen
name="Settings"
component={SettingsScreen}
options={{
header: ({ navigation, scene }) => (
<Header title="Settings" scene={scene} navigation={navigation} />
),
cardStyle: { backgroundColor: "#F8F9FE" }
}}
/>
<Stack.Screen
name="Agreement"
component={AgreementScreen}
options={{
header: ({ navigation, scene }) => (
<Header
back
title="Agreement"
scene={scene}
navigation={navigation}
/>
),
cardStyle: { backgroundColor: "#F8F9FE" }
}}
/>
<Stack.Screen
name="Privacy"
component={PrivacyScreen}
options={{
header: ({ navigation, scene }) => (
<Header
back
title="Privacy"
scene={scene}
navigation={navigation}
/>
),
cardStyle: { backgroundColor: "#F8F9FE" }
}}
/>
<Stack.Screen
name="About"
component={AboutScreen}
options={{
header: ({ navigation, scene }) => (
<Header back title="About" scene={scene} navigation={navigation} />
),
cardStyle: { backgroundColor: "#F8F9FE" }
}}
/>
<Stack.Screen
name="NotificationsSettings"
component={NotificationsScreen}
options={{
header: ({ navigation, scene }) => (
<Header
back
title="Notifications"
scene={scene}
navigation={navigation}
/>
),
cardStyle: { backgroundColor: "#F8F9FE" }
}}
/>
<Stack.Screen
name="Cart"
component={Cart}
options={{
header: ({ navigation, scene }) => (
<Header
back
title="Shopping Cart"
scene={scene}
navigation={navigation}
/>
),
cardStyle: { backgroundColor: "#F8F9FE" }
}}
/>
<Stack.Screen
name="Notifications"
component={NotificationsStack}
options={{
header: ({ navigation, scene }) => (
<Header
back
title="Notifications"
scene={scene}
navigation={navigation}
/>
),
cardStyle: { backgroundColor: "#F8F9FE" }
}}
/>
</Stack.Navigator>
);
}
function ArticlesStack() {
return (
<Stack.Navigator mode="card" headerMode="screen">
<Stack.Screen
name="Articles"
component={Articles}
options={{
header: ({ navigation, scene }) => (
<Header title="Articles" navigation={navigation} scene={scene} />
),
cardStyle: { backgroundColor: "#F8F9FE" }
}}
/>
</Stack.Navigator>
);
}
function ProfileStack() {
return (
<Stack.Navigator initialRouteName="Profile" mode="card" headerMode="screen">
<Stack.Screen
name="Profile"
component={Profile}
options={{
header: ({ navigation, scene }) => (
<Header
transparent
white
title="Profile"
navigation={navigation}
scene={scene}
back={true}
/>
),
cardStyle: { backgroundColor: "#FFFFFF" },
headerTransparent: true
}}
/>
<Stack.Screen
name="Cart"
component={Cart}
options={{
header: ({ navigation, scene }) => (
<Header
back
title="Shopping Cart"
navigation={navigation}
scene={scene}
/>
),
cardStyle: { backgroundColor: "#FFFFFF" }
}}
/>
<Stack.Screen
name="Notifications"
component={NotificationsStack}
options={{
header: ({ navigation, scene }) => (
<Header
back
title="Notifications"
navigation={navigation}
scene={scene}
/>
),
cardStyle: { backgroundColor: "#FFFFFF" }
}}
/>
</Stack.Navigator>
);
}
function FeedStack() {
return (
<Stack.Navigator mode="card" headerMode="screen">
<Stack.Screen
name="Feed"
component={BottomTabStack}
options={{
header: ({ navigation, scene }) => (
<Header
title="Feed"
navigation={navigation}
scene={scene}
/>
),
cardStyle: { backgroundColor: "#F8F9FE" }
}}
/>
<Stack.Screen
name="Search"
component={Search}
options={{
header: ({ navigation, scene }) => (
<Header title="Search" back navigation={navigation} scene={scene} />
),
cardStyle: { backgroundColor: "#F8F9FE" }
}}
/>
</Stack.Navigator>
);
}
function AppStack() {
return (
<Drawer.Navigator
style={{ flex: 1 }}
drawerContent={props => <CustomDrawerContent {...props} />}
drawerStyle={{
backgroundColor: "white",
width: width * 0.8
}}
drawerContentOptions={{
activeTintcolor: "white",
inactiveTintColor: "#000",
activeBackgroundColor: "transparent",
itemStyle: {
width: width * 0.75,
backgroundColor: "transparent",
paddingVertical: 16,
paddingHorizonal: 12,
justifyContent: "center",
alignContent: "center",
alignItems: "center",
overflow: "hidden"
},
labelStyle: {
fontSize: 18,
marginLeft: 12,
fontWeight: "normal"
}
}}
initialRouteName="Feed"
>
<Drawer.Screen name="Feed" component={FeedStack} />
<Drawer.Screen name="Profile" component={ProfileStack} />
<Drawer.Screen name="Account" component={Register} />
<Drawer.Screen name="Elements" component={ElementsStack} />
<Drawer.Screen name="Articles" component={ArticlesStack} />
<Drawer.Screen name="Settings" component={SettingsStack} />
<Drawer.Screen name="NerdList" component={NerdListStack} />
</Drawer.Navigator>
);
}
export default function OnboardingStack() {
return (
<Stack.Navigator mode="card" headerMode="none">
<Stack.Screen
name="Onboarding"
component={Pro}
option={{
headerTransparent: true
}}
/>
<Stack.Screen name="App" component={AppStack} />
</Stack.Navigator>
);
}
As #satya164 pointed out in a comment here, the problem was that I was passing a param to a nested navigator incorrectly. I was attempting to pass the param with:
onPress={() => this.props.navigation.navigate('Profile', {test: 'Hello'})}
The correct way to pass a param to a nested navigator is:
onPress={() => this.props.navigation.navigate('Profile', {screen: 'Profile', params: {test: 'name'}})}