I have two stack navigators for my app. Only one should show up, based of the isLoggedIn condition. However, both show when isLoggedIn = true. But when I set the condition to false, it only shows app. I simply dont get it.
export default function App() {
const isLoggedIn = true;
return (
<NavigationContainer>
<Stack.Navigator>
{isLoggedIn === true ? (
<Stack.Screen name="Auth" component={AuthStackNavigator} />
) : (
<Stack.Screen name="App" component={AppBottomTabNavigator} />
)}
</Stack.Navigator>
</NavigationContainer>
);
}
When isLoggedIn is set to true
When isLoggedIn is set to false
Could you try this.
export default function App() {
const isLoggedIn = true;
return (
<NavigationContainer>
<Stack.Navigator>
{isLoggedIn === true && <Stack.Screen name="Auth" component={AuthStackNavigator} />}
{isLoggedIn === false && <Stack.Screen name="App" component={AppBottomTabNavigator} />}
</Stack.Navigator>
</NavigationContainer>
);
}
Related
Hello I am new to react native and particullary react navigation.
I am stuck on one easy thing, use the tab navigator and the stack navigator at the same time.
I am able to use one at a time but not both at the same time. I didn't fully understood the react navigation doc.
Here is what I am doing :
My navigation file : at first my stack Navigator :
const Stack = createStackNavigator()
export default function MyStack() {
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{headerShown: false}}>
<Stack.Screen name="Profile" component={Profile}/>
<Stack.Screen name="Home" component={Home}/>
<Stack.Screen name="MachinesList" component={MachinesList}/>
<Stack.Screen name="Size" component={Size}/>
<Stack.Screen name="Weight" component={Weight}/>
</Stack.Navigator>
</NavigationContainer>
)
}
and then my tab navigator :
const Tab = createBottomTabNavigator()
export function TabNavigator(){
return(
<Tab.Navigator>
<Tab.Screen name='Profile' component={Profile}/>
<Tab.Screen name='Home' component={Home}/>
<Tab.Screen name='MachinesList' component={MachinesList}/>
</Tab.Navigator>
)
}
And here is how I try to put my navigation in my App.js :
return (
<Provider store={store}>
<MyStack />
</Provider>
You need to define which screens are located in which tabs. Currently, you have three tabs that hold screens that are all located on the same stack.
Usually, this works as follows.
Define a tab navigator with n tabs
Define n stacks
Assign each stack to the corresponding tab
Assign the screens to their stacks
In your case, this looks as follows.
const Tab = createBottomTabNavigator()
export function TabNavigator() {
return (
<Tab.Navigator>
<Tab.Screen name='Profile' component={ProfileStack}/>
<Tab.Screen name='Home' component={HomeStack}/>
<Tab.Screen name='MachinesList' component={MachineListStack}/>
</Tab.Navigator>
)
}
The HomeStack then looks as follows.
const Stack = createStackNavigator()
const HomeStack = () => {
return (
<Stack.Navigator initialRoutName="HomeScreen">
<Stack.Screen name="HomeScreen" component={HomeScreen} />
// all other screens located inside the stack of the tab Home
</Stack.Navigator>
)
}
Do the same for all other stacks. Now, you have three tabs with three stacks. You can nest as many screens inside each stack as you like.
In your main application, you then initialize the TabNavigator.
export default function App() {
return (
<NavigationContainer>
<TabNavigator />
</NavigationContainer>
);
}
You need to add your TabNavigator as a Stack.Screen within Stack.Navigator.
const Stack = createStackNavigator()
export default function MyStack() {
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{headerShown: false}}>
<Stack.Screen name="Profile" component={TabNavigator}/>
<Stack.Screen name="Home" component={Home}/>
<Stack.Screen name="MachinesList" component={MachinesList}/>
<Stack.Screen name="Size" component={Size}/>
<Stack.Screen name="Weight" component={Weight}/>
</Stack.Navigator>
</NavigationContainer>
)
}
You can see now that Profile Stack.Screen are using TabNavigator.
I'm again asking a question regarding ReactNative: I have the following App.js:
export default function App() {
function Tabs() {
return <TabBar />;
}
const styles = StyleSheet.create({
backButton: {
color: global.GUI.ORANGE,
},
});
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Tabs"
component={Tabs}
..
/>
<Stack.Screen
name="Impostazioni"
component={Settings}
...
/>
<Stack.Screen
name="Registrati"
component={Signup}
...
/>
<Stack.Screen
name="Login"
component={Login}
...
/>
</Stack.Navigator>
</NavigationContainer>
);
}
I want to pass to each component some values declared in App.js,but doing something like:
<Stack.Screen
name="Impostazioni"
component={Settings}
currentUser={"name":"test"}
/>
Return undefined in:
import React from 'react';
import {View,Text} from 'react-native';
const Settings = (props) => {
--> console.log(props.currentUser) // here is undefined
return (
<View >
<Text>This is Settings!</Text>
</View>
);
};
export default Settings
So, how can I correctly pass props to App.js to all other components?
Thanks
You have to either use React Context(recommended) or pass props to your component.
https://wix.github.io/react-native-navigation/docs/third-party-react-context/
Another way:
<Stack.Navigator initialRouteName="LoginScreen" headerMode="none">
<Stack.Screen name="LoginScreen" component={LoginScreen} initialParams={{'key':'value'}} />
<Stack.Screen name="CodeVerificationScreen" component={CodeVerificationScreen} initialParams={{'key':'value'}} />
</Stack.Navigator>
You can receive initial params in login.js
console.log(this.props.route.params.key)
Another approach:
Pass props to component - Documentation link:(Please check for your nav version)
https://reactnavigation.org/docs/hello-react-navigation/#passing-additional-props
I have been using React navigation v4 since I am coding in react native. Recently I switched to v6 in a new project, when I needed to setup switchNavigation as I have in v4, I found there was no proper documentation on their site. I tried few ways but it couldn't get me to the desired result. Did anyone of you guys has their setup in v6 of switchNavigation? If so, do share and help me out.
Use async storage , Context APIenter code here
<NavigationContainer theme={MyTheme}>
<Stack.Navigator
screenOptions={{
headerShown: false,
presentation: 'card',
}}
initialRouteName="Landing" //TODO: change to Landing or comment it ;)
// detachInactiveScreens={true}
>
{props.shared.isloginHost == null ? (
<>
<Stack.Screen name="Landing" component={Landing} />
<Stack.Screen name="SignIn" component={SignIn} />
<Stack.Screen name="SignUp" component={SignUp} />
<Stack.Screen name="SignUpDetails" component={SignUpDetails} />
<Stack.Screen name="ForgotPassword" component={ForgotPassword} />
<Stack.Screen name="OTPPassword" component={OTPPassword} />
<Stack.Screen name="ChangePassword" component={ChangePassword} />
<Stack.Screen
name="GuestBottomTab"
component={GuestBottomTabs}
/>
</>
) : (
<>
{props.shared.isloginHost == false ? (
<Stack.Screen
name="GuestBottomTabs"
component={GuestBottomTabs}
/>
) : (
<>
{props.shared.hostplan == null ? (
<Stack.Screen name="Insight" component={Insight} />
) : null}
<Stack.Screen
name="HostBottomTabs"
component={HostBottomTabs}
/>
</>
)}
</>
)}
props.shared.isloginHost isloginHost is the state in the shared reducer when the state is null then user only access the Auth screen
I have been struggling with this for days now... When I try to login it does not automatically navigate me to home screen, unless I close and open app.
I am working with 3 separate components. However after I register once, this issue doesn't occur it only happens with new accounts.
const [userAuth, setUserAuth] = useState()
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
user && auth.currentUser?.emailVerified ? setUserAuth(true) : setUserAuth(false)
})
return unsubscribe
})
return (
<Provider store={store}>
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen
name='main'
component={userAuth ? MainDrawer : AuthStack}
/>
</Drawer.Navigator>
</NavigationContainer>
</Provider>
This is my MainDrawer.js
export default function MainDrawer() {
return (
<Drawer.Navigator drawerContent={props => <DrawerScreen {...props} />}>
<Drawer.Screen
name='drawer'
component={HomeStack}
options={{ headerShown: false }}
/>
</Drawer.Navigator>
)
}
This is my HomeStack.js
<Stack.Navigator initialRouteName='home'>
<Stack.Screen name='home' component={TabNav}/>
<Stack.Screen name='about' component={AboutUs}/>
<Stack.Screen name='faq' component={FaqScreen}/>
<Stack.Screen name='userTerms' component={TermsScreen} />
<Stack.Screen name='privacy' component={PrivacyScreen} />
</Stack.Navigator>
I believe the issue is where you're trying to call onAuthStateChanged, it should be auth().onAuthStateChanged(...). Also, I would change it a little bit
useEffect(() => {
const unsubscribe = auth().onAuthStateChanged(firebaseUserResult => {
firebaseUserResult && firebaseUserResult.emailVerified ? setUserAuth(true) : setUserAuth(false)
})
return unsubscribe
})
I have a really strange problem and so far could not identify the possible weak points.
I have a firebase & react-native application with a nested login.
The problem is the navigation. The drawer and the stack navigation works fine, except for the login screen.
When I try to login and the isSignedIn variable becomes true, the screen is not changing for the home screen. It remains the login screen. However, on the console, I see the authentication was successful. If I go back to the code and click a save in the Navigation file (which was posted here), the forced reload seems to solve the problem and I can see the home screen. But this is not automatically.
So confused.
export default function Navigator() {
const user = firebase.auth().currentUser;
const [isSignedIn, setIsSignedIn] = useState(false)
useEffect( () => {
user ? setIsSignedIn(true) : setIsSignedIn(false)
if (isSignedIn) storeData(user)
})
const storeData = async (value) => {
try {
await AsyncStorage.setItem('userObject', JSON.stringify(value))
alert('Data successfully saved to the storage')
} catch (e) {
alert('Failed to save the data to the storage')
}
}
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Login">
{isSignedIn ? (
<>
<Stack.Screen name='loggedInUserNavigationStack' component={loggedInUserNavigationStack} options={{headerShown: false}}>
</Stack.Screen>
</>
) : (
<Stack.Screen name="Log in" component={LoginScreen} options={{headerShown: false}} />
)}
</Stack.Navigator>
</NavigationContainer>
);
}
function loggedInUserNavigationStack() {
return (
<Drawer.Navigator initialRouteName="mainContentNavigator" drawerContent={ props => <DrawerContent {...props} /> }>
<Drawer.Screen name="mainContentNavigator" component={mainContentNavigator} options={{ title: 'Home' }} />
<Drawer.Screen name="About" component={AboutScreen} options={{ title: 'About' }}/>
<Drawer.Screen name="Archive" component={ArchiveScreen} options={{ title: 'Archive' }}/>
<Drawer.Screen name="Profile" component={ProfileScreen} options={{ title: 'Profile' }} />
<Drawer.Screen name="Sign Out" component={SignOutScreen} options={{headerShown: false}}/>
</Drawer.Navigator>
);
}
function mainContentNavigator() {
return (
<Stack.Navigator initialRouteName="HomeScreen">
<Stack.Screen name="Home" component={HomeScreen} options={
({ navigation }) => {
return {
headerLeft: () => <Header navigation={navigation} />
}
}
} />
<Stack.Screen name="CertainHabbit" component={CertainHabbit} options={({ route }) => ({ title: route.params.name })} />
</Stack.Navigator>
);
}
Firebase automatically tries to restore the signed-in user when you load the page. But since this requires an async call to the server, it may take some time. Right now, by the time your const user = firebase.auth().currentUser runs, the user hasn't been authenticated yet. And by the time the authentication finishes, your code isn't aware of it.
The solution is to use an auth state listener, as shown in the first snippet of the documentation on determining the signed in user. For you that'd be something like this:
useEffect( () => {
firebase.auth().onAuthStateChanged((user) => {
setIsSignedIn(!!user);
if (user) storeData(user)
});
})
Please try,
<NavigationContainer>
<Stack.Screen name="Login" component={LoginScreen} options={{headerShown: false}} />
</NavigationContainer>
You have given initial route name has initialRouteName="Login"
I do see a space in the stack screen.
Try the following for return part:
return isSignedIn ? (
<NavigationContainer>
<Stack.Screen name='loggedInUserNavigationStack' component={loggedInUserNavigationStack} options={{headerShown: false}} />
</NavigationContainer>
):(
<NavigationContainer>
<Stack.Screen name="Login" component={LoginScreen} options={{headerShown: false}} />
</NavigationContainer>
)