I am using tabnavigator and stacknavigator, and after my connection I cannot be redirected to my home navigation unless I add Home to my stacknavigator, but tabnavigator disappears. I would like to know what I should do to be sent to my home navigation, so that my tabnavigator does not disappear.
const [user, setUser] = useState(false);
useEffect(()=> {
setTimeout(() => {
User()
console.log("Update")
}, 500);
},)
const User = async() => {
const value = await AsyncStorage.getItem('#user')
if (value === null) {
console.log('disconnecte')
}else {
setUser(true)
console.log("online")
navigation.navigate('Home')
}
}
return (
<NavigationContainer>
{user === false ? <Authnavigator/> : <Stacknavigator /> }
</NavigationContainer>
)
}
StackNavigator
export default function Stacknavigator() {
return (
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
headerShown: false
}}>
<Stack.Screen name="TabNavigator" component={TabNavigator} />
<Stack.Screen name="Details" component={Details} />
</Stack.Navigator>
)
}
Authnavigator
export default function Authnavigator() {
return (
<AuthStack.Navigator screenOptions={{
headerShown: false
}}>
<AuthStack.Screen name="Login" component={Login} />
</AuthStack.Navigator>
)
}
Update :
the login navigation to Home works but then to go to the Details view it does not work
export default function Stacknavigator() {
return (
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
headerShown: false
}}>
<Stack.Screen name="Tabnavigator" component={Tabnavigator} />
<Stack.Screen name="Details" component={Details} />
</Stack.Navigator>
)
}
Tabnavigator
export default function Tabnavigator() {
return (
<Tab.Navigator
initialRouteName="Home"
activeColor="#f0edf6"
inactiveColor="#6D6D6D"
barStyle={{ backgroundColor: '#171717' }}
>
<Tab.Screen name="Home" component={Home} options= {{
tabBarIcon: ({ color }) => (
<FontAwesome name="home" size={20} color={(color)} />
)
}} />
<Tab.Screen name="Recherche" component={Search} options={{
tabBarIcon: ({color}) => (
<FontAwesome name="search" size={20} color={(color)} />
)
}} />
<Tab.Screen name="Favorie" component={Favorie} options={{
tabBarIcon: ({color}) => (
<FontAwesome name="star" size={20} color={(color)} />
)
}}/>
</Tab.Navigator>
)
}
const Tab = createMaterialBottomTabNavigator();
Authnavigator
export default function Authnavigator() {
return (
<AuthStack.Navigator screenOptions={{
headerShown: false
}}>
<AuthStack.Screen name="Login" component={Login} />
<AuthStack.Screen name="Tabnavigator" component={Tabnavigator} />
</AuthStack.Navigator>
)
}
You don't have an initialRouteName Home in your Stack.Navigator. You need to point it to TabNavigator so that your code should look like this.
export default function Stacknavigator() {
return (
<Stack.Navigator
initialRouteName="TabNavigator"
screenOptions={{
headerShown: false
}}>
<Stack.Screen name="TabNavigator" component={TabNavigator} />
<Stack.Screen name="Details" component={Details} />
</Stack.Navigator>
)
}
Related
I have a drawer navigation configured in the following way:
const CustomDrawerContent = () => { return ( <DrawerItem label="Log out2" onPress={() => logOut()} /> ) }
const loginStack = () => (
<Stack.Navigator >
<Stack.Screen name='LandingScreen' component={LandingScreen} options={{headerShown: false}} />
<Stack.Screen name='LoginScreen' component={LoginScreen} options={{headerShown: false}} />
<Stack.Screen name='RegisterScreen' component={RegisterScreen} options={{headerShown: false}} />
</Stack.Navigator>
)
return (
<NavigationContainer>
<Drawer.Navigator
screenOptions={{
drawerStyle: { backgroundColor: 'white' },
drawerPosition: 'right'
}}>
{!user ? (
<Drawer.Screen
name="PublicStack"
component={loginStack}
options={{headerShown: false}}
/> )
:
(<>
<Drawer.Screen name='Search cocktails' component={HomeScreen} options={{ header: () => <Header/> }} />
<Drawer.Screen name='Profile' component={ProfileScreen} options={{ header: () => <Header/> }} />
<Drawer.Screen name='Publish a recipe' component={PublishRecipeScreen} options={{ header: () => <Header/> }} />
<Drawer.Screen name='Favorites' component={FavoritesScreen} options={{ header: () => <Header/> }} />
<Drawer.Screen name='Published recipes' component={PublishedRecipesScreen} options={{ header: () => <Header/> }} />
<Drawer.Screen name='Log out' component={CustomDrawerContent} options={{ header: () => <Header/> }} />
<Drawer.Screen name='CocktailDetailScreen' component={CocktailDetailScreen} options={{
header: () => <Header/>,
drawerLabel: () => null,
title: undefined
}} />
</>
)}
</Drawer.Navigator>
</NavigationContainer>
)
All screens work fine, but I want Log out to execute a logout function onPress. As I understand, I can't add this event listener directly on the screen component, so I followed this doc (https://reactnavigation.org/docs/drawer-navigator/#drawercontent) and tried a few different things:
I created the component CustomDrawerContent which is a DrawerItem.
If I pass CustomDrawerContent as the component to the Log out screen (as the code is right now), when I click on it I get redirected to a blank page that renders CustomDrawerContentcomponent, which isn't what I want.
If I pass CustomDrawerContent as drawerContent props to the drawer navigator, like the doc says (example below), all other screens dont render anymore, which is again not what I want.
<Drawer.Navigator drawerContent={(props) => <CustomDrawerContent />}>
{/* screens */}
</Drawer.Navigator>
If I put the drawer item together with the screens inside the navigator, the app throws the following error:
useNavigationBuilder.tsx:134 Uncaught Error: A navigator can only contain 'Screen', 'Group' or 'React.Fragment' as its direct children (found 'DrawerItem'). To render this component in the navigator, pass it in the 'component' prop to 'Screen'.
So how can I add the item to the drawer without 'overwritting' the screens?
Or is there other way to put a simple logout button in the drawer?
Full code can be found here: https://github.com/coccagerman/mixr
I have a navigator as below. I want to show the drawer when the user logged in. However, the isLogin will still be false after I login. As I am quit new to react native, is there any solution to this issue? Also, I want to know if there are any good sources for learning react native?
let isLogin = firebase.auth().currentUser ? true : false;
const HomeStack = () => {
return (
<Stack.Navigator
screenOptions={{
headerStyled: {
backgroundColor: primary,
},
headerLeftContainerStyle: {
paddingLeft: 20,
},
headerShown: false,
}}
initialRouteName="Home"
>
<Stack.Screen name="HomeScreen" component={Home} />
<Stack.Screen name="Login" component={Login} />
</Stack.Navigator>
);
};
console.log(isLogin);
const LoginStack = () => {
return (
<Stack.Navigator
screenOptions={{
headerStyled: {
backgroundColor: primary,
},
headerLeftContainerStyle: {
paddingLeft: 20,
},
headerShown: false,
}}
initialRouteName="Login"
>
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="Signup" component={Signup} />
<Stack.Screen name="Home" component={Home} />
</Stack.Navigator>
);
};
const RootStack = () => {
return (
<NavigationContainer>
{/* {isLogin ? (
<Drawer.Navigator>
<Drawer.Screen name="Home" component={HomeStack} />
<Drawer.Screen name="Chat" component={Chat} />
</Drawer.Navigator>
) : (
<LoginStack />
)} */}
<LoginStack />
</NavigationContainer>
);
};
export default RootStack;
Because you initialize isLogin variable outside the component, you get value only one time. So you need to put declaring variable into the component.
const RootStack = () => {
let isLogin = firebase.auth().currentUser ? true : false;
return (
<NavigationContainer>
{/* {isLogin ? (
<Drawer.Navigator>
<Drawer.Screen name="Home" component={HomeStack} />
<Drawer.Screen name="Chat" component={Chat} />
</Drawer.Navigator>
) : (
<LoginStack />
)} */}
<LoginStack />
</NavigationContainer>
);
};
I followed the React Navigation Doc to achieve a Dynamic header title change but It shows the error Undefined is not an object (evaluating 'route.params.title').
My tabs.js:
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
<HomeStack.Screen
name="Profile"
component={Profile}
options={({ route }) => ({ title: route.params.title })}
/>
</HomeStack.Navigator>
);
}
The Home.js has the onpress like that:
<TouchableOpacity
onPress={() => {
navigation.navigate('Profile', {
title: 'Custom title',
});
}}
>
And Profile.js:
function Profile({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Hello</Text>
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
);
}
Add a check/default value on your params, because route.params is not always valorized, but only when you navigate on that page.
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
<HomeStack.Screen
name="Profile"
component={Profile}
options={({ route }) => ({ title: route.params?.title || "DEFAULT TITLE" })}
/>
</HomeStack.Navigator>
);
}
I am trying to use the navigation prop inside my Stack Navigator to open the drawer when the material icon is clicked. However when I click th button I recieve the error:
Undefined is not an object (evaluating navigation.openDrawer)
I am confused as I have passed the navigation prop into the 'App' function. Where am I going wrong here?
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {createDrawerNavigator} from '#react-navigation/drawer';
import HomeScreen from './src/screens/HomeScreen';
import SecondScreen from './src/screens/SecondScreen.js';
import {MaterialIcons} from '#expo/vector-icons';
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator();
const TheDrawer = () => {
return(
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="SecondScreen" component={SecondScreen} />
</Drawer.Navigator>
);
}
const App = ({navigation}) =>{
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
name="Home"component={TheDrawer}
options={{headerTitle:
<View>
<MaterialIcons
name='menu'
onPress={() => navigation.openDrawer()} size={28}
/>
</View>
}}
/>
<Stack.Screen name="SecondScreen" component={SecondScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default App;
The navigation prop only exist inside a Navigator, and different Navigators will have different navigation props (the Stack Navigator navigation will NOT have the openDrawer method, for example). I think that what you want to accomplish is this:
const App = () => {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen
name="Home"
component={HomeScreen}
options={({ navigation }) => ({
headerTitle: (
<View>
<MaterialIcons name="menu" onPress={() => navigation.openDrawer()} size={28}/>
</View>
),
})}
/>
<Drawer.Screen name="SecondScreen" component={SecondScreen} />
</Drawer.Navigator>
</NavigationContainer>
);
};
Or, if you want the menu button available on every page header:
const App = () => {
return (
<NavigationContainer>
<Drawer.Navigator
initialRouteName="Home"
screenOptions={({ navigation }) => ({
headerTitle: (
<View>
<MaterialIcons name="menu" onPress={() => navigation.openDrawer()} size={28} />
</View>
),
})}
>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="SecondScreen" component={SecondScreen} />
</Drawer.Navigator>
</NavigationContainer>
);
};
Source: https://reactnavigation.org/docs/headers/
If you need to access more pages inside this two (Home, SecondScreen), you can create it like this:
const HomeScreen = () => {
<Stack.Navigator>
<Stack.Screen name="Home1" component={HomeScreen1} />
<Stack.Screen name="Home2" component={HomeScreen2} />
<Stack.Screen name="Home3" component={HomeScreen3} />
</Stack.Navigator>
}
Source: https://reactnavigation.org/docs/nesting-navigators
I'm trying to navigate to my Login screen, but I haven't defined my Login screen in my NavigationContainer. This is because I don't want the Login screen to be a tab in my navbar. This leads to my question: Is there a way to navigate to the Login screen, without having it as a tab in the navbar?
export default function App() {
return (
<NavigationContainer>
<SafeAreaView style={{flex: 1}}>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'Home') {
iconName = focused
? 'home-outline'
: 'home-outline';
} else if (route.name === 'Profile') {
iconName = focused ? 'person-circle-outline' : 'person-circle-outline';
} else if (route.name === 'Calendar') {
iconName = focused ? 'calendar-clear' : 'calendar-clear';
} else if (route.name === 'Agenda') {
iconName = focused ? 'calendar-outline' : 'calendar-outline';
}
return <Ionicons name={iconName} size={size} color={color} />;
},
})}
tabBarOptions={{
activeTintColor: 'blue',
inactiveTintColor: 'gray',
}}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
<Tab.Screen name="Calendar" component={CalendarScreen} />
<Tab.Screen name="Agenda" component={AgendaScreen} />
<Tab.Screen name="New Event" component={NewEventScreen} />
</Tab.Navigator>
</SafeAreaView>
</NavigationContainer>
);
}
<Button
title="Do you have an account? Click here to log in"
onPress={() => this.props.navigation.navigate("Login")}
/>
This is an example of how it can be done:
private render() {
const Stack = createStackNavigator();
const landingScreen = this.props.isLoggedIn ? null : (
<Stack.Screen
name="LoginScreen"
component={LoginScreen}
/>
);
return (
<NavigationContainer>
<Stack.Navigator>
{landingScreen}
<Stack.Screen name="HomeScreen" component={this.renderTabNavigator}/>
</Stack.Navigator>
</NavigationContainer>
);
}
private renderTabNavigator = () => {
const Tab = createBottomTabNavigator();
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={SearchScreen}/>
<Tab.Screen name="Favorites" component={FavoritesScreen}/>
<Tab.Screen name="Settings" component={SettingsScreen}/>
</Tab.Navigator>
);
}