so I 've got nested navigation, as the code shows. Now I am trying to make the header bar. however, when I change the screens from bottom navigation the header remains the same, no matter on what screen I am(always shoes that I am on Browser screen). Also is the React navigation header the best to create a header bar or is better to create a fully custom one. Thank you
I am expecting that the header title will change in accordance with the page.
const Stack = createStackNavigator();
const Tabs = createMaterialBottomTabNavigator();
const AuthStack = createStackNavigator();
const TabsScreen = () => (
<Tabs.Navigator shifting={true} initialRouteName="Home" activeColor="#fff">
<Tabs.Screen
name="Home"
component={Browser}
options={{
tabBarLabel: 'Home',
tabBarColor: '#009387',
tabBarIcon: ({color}) => (
),
}}
/>
<Tabs.Screen
name="Sleep"
component={Sleep}
options={{
tabBarLabel: 'Sleep',
tabBarColor: '#694fad',
tabBarIcon: ({color}) => (
),
}}
/>
<Tabs.Screen
name="Settings"
component={SettingWithContext}
options={{
tabBarLabel: 'Settings',
tabBarColor: '#694fad',
tabBarIcon: ({color}) => (
),
}}
/>
</Tabs.Navigator>
);
export default CreateStack = () => {
const [isLoading, setIsLoading] = React.useState(true);
const [userToken, setUserToken] = React.useState(null);
const authContext = React.useMemo(() => {
return {
signIn: () => {
setIsLoading(false);
setUserToken('asdf');
},
signUp: () => {
setIsLoading(false);
setUserToken('asdf');
},
signOut: () => {
setIsLoading(false);
setUserToken(null);
},
};
}, []);
React.useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 1000);
}, []);
if (isLoading) {
return ;
}
return (
<AuthContext.Provider value={authContext}>
{userToken ? (
<Stack.Navigator initialRouteName={Browser}>
<Stack.Screen name="Browser" component={TabsScreen} />
<Stack.Screen name="PreScreen" component={PreScreen} />
<Stack.Screen name="Player" component={Player} />
</Stack.Navigator>
) : (
<AuthStack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={RegisterLogin}>
<AuthStack.Screen name="RegisterLogin" component={RegisterLogin} />
<AuthStack.Screen name="Login" component={LoginWithContext} />
<AuthStack.Screen name="Register" component={RegisterWithContext} />
</AuthStack.Navigator>
)}
</AuthContext.Provider>
);
};
If you want to have every tab name to be the top try this: https://reactnavigation.org/docs/screen-options-resolution/
Check out the getHeaderTitle function and the switch statement below that - it helped me achieve this behavoir.
Because you are using nested navigation, and the stack navigator is the parent one, the top header will remain the same for any navigator inside the TabNavigator.
You might want to create instead a stack navigator inside each tab, so each tab will have its own header title and navigation path.
In another hand, you could try using screen options in order to create some business logic to determine which title you want based on the navigation state.
For example:
const Stack = createStackNavigator();
const Tabs = createMaterialBottomTabNavigator();
const AuthStack = createStackNavigator();
const TabsScreen = () => (
<>
<Tabs.Navigator shifting={true} initialRouteName="Home" activeColor="#fff">
<Tabs.Screen
name="Home"
component={Browser}
options={{
tabBarLabel: "Home",
tabBarColor: "#009387",
tabBarIcon: ({ color }) => color,
}}
/>
<Tabs.Screen
name="Sleep"
component={Sleep}
options={{
tabBarLabel: "Sleep",
tabBarColor: "#694fad",
tabBarIcon: ({ color }) => color,
}}
/>
<Tabs.Screen
name="Settings"
component={SettingWithContext}
options={{
tabBarLabel: "Settings",
tabBarColor: "#694fad",
tabBarIcon: ({ color }) => color,
}}
/>
</Tabs.Navigator>
</>
);
let CreateStack = () => {
const [isLoading, setIsLoading] = React.useState(true);
const [userToken, setUserToken] = React.useState(null);
const authContext = React.useMemo(() => {
return {
signIn: () => {
setIsLoading(false);
setUserToken("asdf");
},
signUp: () => {
setIsLoading(false);
setUserToken("asdf");
},
signOut: () => {
setIsLoading(false);
setUserToken(null);
},
};
}, []);
React.useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 1000);
}, []);
if (isLoading) {
return;
}
return (
<AuthContext.Provider value={authContext}>
{userToken ? (
<Stack.Navigator initialRouteName={Browser}>
{/* Added the options prop to the Browser screen*/}
<Stack.Screen
name="Browser"
component={TabsScreen}
options={({ route }) => ({
headerTitle: getHeaderTitle(route),
})}
/>
<Stack.Screen name="PreScreen" component={PreScreen} />
<Stack.Screen name="Player" component={Player} />
</Stack.Navigator>
) : (
<AuthStack.Navigator
screenOptions={{ headerShown: false }}
initialRouteName={RegisterLogin}
>
<AuthStack.Screen name="RegisterLogin" component={RegisterLogin} />
<AuthStack.Screen name="Login" component={LoginWithContext} />
<AuthStack.Screen name="Register" component={RegisterWithContext} />
</AuthStack.Navigator>
)}
</AuthContext.Provider>
);
};
/**
* Method to get the route name based on the component.
*/
const getHeaderTitle = (route) => {
if (route === "Browser") {
return "Home";
} else if (route === "Sleep") {
return "Sleep"
} else if (route === "Settings") {
return "Settings";
} else {
return route;
}
}
export default CreateStack;
The header is a thing in the stack navigation, not however in the tab-navigation.
Your App is using the header of the stack-navigator in which the tab-navigator is nested.
You could nest stack navigators inside your Tab-Navigator to have the header change as you need it to.
Related
I'm confused on how can I show my customDialog whenever I don't have Internet connection to my app, Currently, I've only managed to show my customDialog within LoginScreen , I just want to show my custom dialog from different screen not only on LoginScreen whenever I don't have Internet connection, what is the best way to implement it ? should I put CustomDialog each of the screen?
Someone have the idea to implement this? need help
screens/LoginScreen
import NetInfo from "#react-native-community/netinfo";
import CustomAlert from '../components/CustomAlert';
const LoginScreen = ({navigation}) => {
const [modalVisible, setModalVisible] = useState(false);
const [internetCon, setNet] = useState(true);
React.useEffect(()=>{
checkInternetConnection();
}, [])
function checkInternetConnection() {
NetInfo.addEventListener(state =>{
if (state.isConnected==false){
setModalVisible(true);
setNet(false);
console.log("Connection types", state.type);
console.log("Your device appears to have no internet connectivity. Please check your connection settings and try again");
}
else{
console.log("Connected to internet?", state.isConnected);
}
});
}
return (
<ScrollView style={styles.container} >
{internetCon ===false ? //Check if Internet Existt
<CustomAlert
modalVisible={modalVisible}
setModalVisible={setModalVisible}
title={'Message'}
message={'Your device appears to have no internet connectivity. Please check your connection settings and try again'}
buttons={[{
text: 'Retry',
func: () => {checkInternetConnection();}
}]}
/>
:null}
</ScrollView>
);
};
export default LoginScreen;
navigation/AppStack.js
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
const FeedStack = ({navigation}) => (
<Stack.Navigator
screenOptions={{
headerShown: false
}}>
<Stack.Screen
name="test"
component={HomeScreen}
options={{
headerTitleAlign: 'center',
headerTitleStyle: {
color: '#2e64e5',
fontFamily: 'Kufam-SemiBoldItalic',
fontSize: 18,
},
headerStyle: {
shadowColor: '#fff',
elevation: 0,
},
headerRight: () => (
<View style={{marginRight: 10}}>
<FontAwesome5.Button
name="plus"
size={22}
backgroundColor="#fff"
color="#2e64e5"
onPress={() => navigation.navigate('AddPost')}
/>
</View>
),
}}
/>
<Stack.Screen
name="HomeProfile"
component={ProfileScreen}
options={{
title: '',
headerTitleAlign: 'center',
headerStyle: {
backgroundColor: '#fff',
shadowColor: '#fff',
elevation: 0,
},
headerBackTitleVisible: false,
headerBackImage: () => (
<View style={{marginLeft: 15}}>
<Ionicons name="arrow-back" size={25} color="#2e64e5" />
</View>
),
}}
/>
</Stack.Navigator>
);
const AppStack = () => {
const getTabBarVisibility = (route) => {
const routeName = route.state
? route.state.routes[route.state.index].name
: '';
if (routeName === 'Chat') {
return false;
}
return true;
};
return (
<Tab.Navigator
screenOptions={{
headerShown: false
}}
tabBarOptions={{
activeTintColor: '#2e64e5',
}}>
<Tab.Screen
name="Home"
component={FeedStack}
options={({route}) => ({
tabBarLabel: 'Home',
// tabBarVisible: route.state && route.state.index === 0,
tabBarIcon: ({color, size}) => (
<MaterialCommunityIcons
name="home-outline"
color={color}
size={size}
/>
),
})}
/>
<Tab.Screen
name="Messages"
component={MessageStack}
options={({route}) => ({
tabBarVisible: getTabBarVisibility(route),
tabBarIcon: ({color, size}) => (
<Ionicons
name="chatbox-ellipses-outline"
color={color}
size={size}
/>
),
})}
/>
</Tab.Navigator>
);
};
export default AppStack;
navigation/AuthProvider.js
export const AuthContext = createContext();
export const AuthProvider = ({children}) => {
const [user, setUser] = useState(null);
const [modalVisible, setModalVisible] = useState(false);
return (
<AuthContext.Provider
value={{
user,
setUser,
googleLogin: async () => {
try {
// Get the users ID token
const Token = await GoogleSignin.signIn();
const {idToken} = Token;
console.log("Processing");
console.log("ok");
// Create a Google credential with the token
const googleCredential = auth.GoogleAuthProvider.credential(idToken);
// Sign-in the user with the credential
await auth().signInWithCredential(googleCredential)
.catch(error => {
console.log('Something went wrong with sign up: ', error);
});
} catch(error) {
// console.log('Something went wrong with sign up: ', error);
}
},
}}>
{children}
</AuthContext.Provider>
);
};
Yo can try react-navigation modal: https://reactnavigation.org/docs/modal/
I pretty much followed both react-navigation deep linking and branch.io react-native documentation, and either both are deprecated or just not completely helpful.
All I want is that whenever a deep link reads from the linking, navigate to a certain screen, I'm not looking to implement a listener on a specific screen, I want this on a root path, and is either the onReady (which for me didn't work) or linking from navigator container
this is my code, very simple
const linking: LinkingOptions = {
prefixes: ['agendameio://', 'https://agendame.io', 'https://agendameio.app.link', 'https://agendameio.app-alternative.link'],
subscribe(listener) {
const navigation = useNavigation();
const onReceiveURL = ({ url }: { url: string }) => listener(url);
Linking.addEventListener('url', onReceiveURL);
branch.skipCachedEvents();
branch.subscribe(async ({ error, params, uri }) => {
if (error) {
console.error('Error from Branch: ' + error);
return;
}
if (params) {
DataManager.DynamicURL = params['~id'] === "951933826563912687" ? params.id : undefined;
}
let url = params?.['+url'] || params?.['~referring_link']; // params !== undefined ? `agendameio://empresa/${params.id}` : 'agendameio://empresa';
navigation.navigate(`DetalleEmpresa${params.id}`);
listener(url);
});
return () => {
Linking.removeEventListener('url', onReceiveURL);
branch.logout();
};
},
I instantly get an error due to use navigation, but I really don't know what else to use to navigate to inside the app
EDIT: this is the error in particular
EDIT 2: I'll add my navigation so it can help to understand my problem
function firstStack() {
return (
<homeStack.Navigator initialRouteName="EmpresasScreen">
<homeStack.Screen
options={({navigation}) => ({
headerShown: false,
headerTitle: () => (
<>
<View style={styles.viewHeader}>
<Image
resizeMode="contain"
style={styles.imageLogo}
source={Images.iconoToolbar}
/>
</View>
</>
),
})}
name="EmpresasScreen"
component={EmpresasScreen}
/>
<detalleEmpresaStack.Screen
options={{ headerShown: false }}
name="DetalleEmpresaScreen"
component={DetalleEmpresaScreen}
/>
<agendamientoStack.Screen
options={{ headerShown: false }}
name="AgendamientoScreen"
component={AgendamientoScreen}
/>
</homeStack.Navigator>
);
}
function secondStack() {
return (
<misCitasStack.Navigator>
<misCitasStack.Screen
options={({navigation}) => ({
headerShown: false,
headerTitle: () => (
<>
<View style={styles.viewHeader}>
<Image
resizeMode="contain"
style={styles.imageLogo}
source={Images.iconoToolbar}
/>
</View>
</>
),
})}
name="MisCitasScreen"
component={CitasScreen}
/>
<detalleCitasStack.Screen
options={({navigation}) => ({
headerShown: false,
})}
name="DetalleCitaScreen"
component={DetalleCitaScreen}
/>
</misCitasStack.Navigator>
);
}
function tabStack() {
return (
<tab.Navigator
screenOptions={({route}) => ({
tabBarIcon: ({focused}) => {
let iconName;
if (route.name === 'Home') {
iconName = focused
? Images.casaActive
: Images.casa
} else if (route.name === 'Citas') {
iconName = focused
? Images.citasActive
: Images.citas
}
return <Image source={iconName} />
}
})}
tabBarOptions={{
showLabel: false,
}}>
<tab.Screen name="Home" component={firstStack} />
<tab.Screen name="Citas" component={secondStack} />
</tab.Navigator>
);
}
function menuStackNavigator() {
useEffect(() => {
VersionCheck.needUpdate({forceUpdate: true}).then(async res => {
if (res.isNeeded) {
alertNeedUpdate(res.storeUrl, false);
}
});
if(Platform.OS === 'android') {
NativeModules.SplashScreenModule.hide();
}
}, [])
return (
<NavigationContainer linking={linking}>
<stack.Navigator headerMode="none">
<stack.Screen name="Home" component={tabStack} />
<stack.Screen name="Error" component={ErrorScreen} />
</stack.Navigator>
</NavigationContainer>
);
};
const styles = StyleSheet.create({
viewHeader: {
alignItems: 'center',
justifyContent: 'center',
},
imageLogo: {
alignItems: 'center',
justifyContent: 'center',
marginTop: 6,
marginBottom: 6
}
});
export default menuStackNavigator;
you can use Configuring links to open the target screen directly.
see more example here configuring-links
Here the URL /feed will open screen named Chat.
import { NavigationContainer } from '#react-navigation/native';
const linking = {
prefixes: ['https://mychat.com', 'mychat://'],
config: {
screens: {
Chat: 'feed/:sort', //URL `/feed` will open screen named `Chat`.
Profile: 'user',
}
},
};
function App() {
return (
<NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>
<Stack.Navigator>
<Stack.Screen name="Chat" component={ChatScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
or use navigationRef.
read about it navigating-without-navigation-prop.
wait to navigation to be ready and then navigate.
import { createNavigationContainerRef } from '#react-navigation/native';
function App() {
const navigationRef = createNavigationContainerRef();
const navigateWhenNavigationReady = (routeName, params, n = 0) => {
setTimeout(() => {
if (navigationRef?.getRootState()) {
navigationRef.navigate(routeName, params)
}else if (n < 100) {
navigateWhenNavigationReady(routeName, params, n + 1);
}
}, 300)
}
const linking = {
...,
subscribe(listener) {
...
navigateWhenNavigationReady("Chat", {id: 123});
}
};
return (
<NavigationContainer ref={navigationRef} linking={linking}>
<Stack.Navigator>
<Stack.Screen name="Chat" component={ChatScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
can you try doing it like this
const App = () => {
return (
<NavigationContainer>
<AppNavigator />
</NavigationContainer>
);
};
and do the subscribe in
export const AppNavigator = () => {
const navigation =useNavigation();
useEffect(()=>{
//add listener and navigation logic here
},[]);
return (
<Stack.Navigator >
...
</Stack.Navigator>
);
};
this will make navigation context to be available in AppNavigator Component
Answer use custom hook useNavigationWhenReady.
const useNavigationWhenReady = (isReady, navigationRef) => {
const [routeName, setRouteName] = React.useState();
const [routeParams, setRouteParams] = React.useState({});
const [navigationAction, setNavigationAction] = React.useState("navigate");
React.useEffect(() => {
if (isReady && routeName) {
if(navigationRef && navigationRef[navigationAction]) {
const _navigationAction = navigationRef[navigationAction];
_navigationAction(routeName, routeParams);
}
}
}, [isReady, routeParams, routeParams]);
const navigate = (_routeName, _routeParams = {}) => {
if(!routeName) {
setNavigationAction("navigate");
setRouteParams(_routeParams);
setRouteName(_routeName);
}
};
const reset = (state) => {
if(!routeName) {
setNavigationAction("reset");
setRouteName(state);
}
};
return { navigate, reset }
};
you can now use useNavigationWhenReady instead of useNavigation;
import { createNavigationContainerRef } from '#react-navigation/native';
function App() {
const [isReady, setReady] = React.useState(false);
const navigationRef = createNavigationContainerRef();
//define it here
const navigation = useNavigationWhenReady(isReady, navigationRef);
const handleOpenNotificationOrOpenLinking = () => {
...
navigation.navigate("screenName", {param1: value1});
//or use reset
//navigation.reset({
//index: 1,
//routes: [{ name: 'screenName' }]
//});
};
return (
<NavigationContainer ref={navigationRef} onReady={() => setReady(true)}>
</NavigationContainer>
);
}
if you use react-navigation-v5 not v6 use
//const navigationRef = createNavigationContainerRef();
//const navigation = useNavigationWhenReady(isReady, navigationRef);
const navigationRef = React.useRef();
const navigation = useNavigationWhenReady(isReady, navigationRef?.current);
you can also show loading or splash screen while navigation not ready
return (
<NavigationContainer ref={navigationRef} onReady={() => setReady(true)}>
<RootStack.Navigator initialRouteName={isReady ? "home" : "loading"} >
</RootStack>
</NavigationContainer>
);
I'm relatively new to React Native and am struggling with screens. I've gone through the nested navigation documentation (https://reactnavigation.org/docs/nesting-navigators/) which helped me setup the initial nav setup i have, but im having some issues.
I'm attempting to setup the app so it has the initial screen as a "Select User" which has no tab navigation. After selecting the user, you are redirected to a another screen which has tab navigation. I currently have it working however I am unable to access any route/props/params after the initial screen.
I've had to manually import navigation with import { useNavigation } from "#react-navigation/native"; and even though I'm providing params in the Navigation.push, trying to access {route} in my screens states that route is undefined.
My setup of the screens looks similar to below:
const Tab = createBottomTabNavigator();
const WelcomeStack = createStackNavigator();
const HomeStack = createStackNavigator();
const SettingsStack = createStackNavigator();
const Stack = createStackNavigator();
const WelcomeStackScreen = () => (
<WelcomeStack.Navigator>
<WelcomeStack.Screen
name="Welcome"
component={WelcomeScreen}
options={{ headerShown: false }}
/>
<WelcomeStack.Screen
name="SignUp"
component={SignUpScreen}
options={{ headerShown: false }}
/>
</WelcomeStack.Navigator>
);
const HomeStackScreen = () => {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen
name="Search"
component={SearchResultScreen}
options={({ navigation }) => ({
headerLeft: () => (
<Ionicons
name={"arrow-back"}
size={30}
color={colours.text}
style={{ paddingLeft: 15 }}
onPress={() => {
navigation.goBack();
}}
/>
),
})}
/>
<HomeStack.Screen
name="Select"
component={SelectScreen}
options={({ navigation, route }) => ({
title: route.params.name,
headerLeft: () => (
<Ionicons
name={"arrow-back"}
size={30}
color={colours.text}
style={{ paddingLeft: 15 }}
onPress={() => {
navigation.goBack();
}}
/>
),
})}
/>
<HomeStack.Screen name="Read" component={ReaderScreen} />
</HomeStack.Navigator>
);
};
function SettingsScreen() {
return (
<View
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
>
<Text>TBD</Text>
</View>
);
}
const SettingsStackScreen = () => (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
</SettingsStack.Navigator>
);
const TabNavigator = ({ route }) => (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
switch (route.name) {
case "Home":
iconName = focused ? "home" : "home-outline";
break;
case "Settings":
iconName = focused ? "list" : "list-outline";
break;
default:
break;
}
return <Ionicons name={iconName} size={size} color={color} />;
},
})}
tabBarOptions={{
activeTintColor: "tomato",
inactiveTintColor: "gray",
}}
>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Settings" component={SettingsScreen}/>
</Tab.Navigator>
);
export default function App() {
return (
<NavigationContainer theme={navThemeOverride}>
<Stack.Navigator>
<Stack.Screen name="Welcome" component={WelcomeStackScreen} />
<Stack.Screen
name="TabNavigator"
component={TabNavigator}
options={{ headerShown: false }}
navigationOptions={{ gesturesEnabled: false }}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
Below is a snippet from the Welcome screen navigation
navigation.push("TabNavigator", {
screen: "Home",
params: {
userId: userId,
},
});
Your Home screen you're trying to navigate to from your parent-tab-navigator ... is also a StackNavigator ... and you wanna navigate to Select screen I guess ... so there's an extra level needed for your navigation to work...
navigation.navigate('TabNavigator', {
screen: 'Home', // <--- StackNavigator
params: {
screen: 'Select', // <-- nested inside HomeStack
params: {
title: 'Your custom title for Select screen here ...',
},
},
});
Plus +
There's a double definition for route in your Tab navigator
const TabNavigator = ({ route }) => ( //<--- here
<Tab.Navigator
screenOptions={({ route }) => ({ // <- and here
Instead
function TabNavigator() {
return <Tab.Navigator screenOptions={({ route }) => ({})>{/* ...Tabs... */}</Tab.Navigator>;
}
I'm using react navigation and Firebase for authentication for a user to move to different screens in my react navigation app.
I created a logout function that signs the user out and takes them to the login screen. However on the upper left corner my app gives the user the option to go back into app without the need to log back in with button labelled as the name of the screen they just logged out of. Is there a way to disable this?
Here is my logout screen :
export default function ProductScreen({ navigation }) {
const logOutPress = () => {
try {
auth()
.signOut()
.then(() => {
navigation.navigate("Login"), alert("You have signed out");
});
} catch (error) {
console.log("err", error);
}
};
return (
<TouchableOpacity onPress={() => logOutPress()}>
<Text style={styles.buttonText}>Log Out</Text>
</TouchableOpacity>
);
}
Also here is my app.js where I house my react navigation and Firebase :
const Stack = createStackNavigator();
export default function App() {
const [loading, setLoading] = useState(true);
const [user, setUser] = useState(null);
useEffect(() => {
const usersRef = firebase.firestore().collection("users");
firebase.auth().onAuthStateChanged((user) => {
if (user) {
usersRef
.doc(user.uid)
.get()
.then((document) => {
const userData = document.data();
setLoading(false);
setUser(userData);
})
.catch((error) => {
setLoading(false);
});
} else {
setLoading(false);
}
});
}, []);
if (loading) {
return <></>;
}
return (
<NavigationContainer>
<Stack.Navigator>
{user ? (
<Stack.Screen name="Products">
{(props) => <ProductScreen {...props} extraData={user} />}
</Stack.Screen>
) : (
<>
<Stack.Screen name="Login" component={LoginScreen} />
</>
)}
<Stack.Screen name="Registration" component={RegistrationScreen} />
<Stack.Screen name="Payment" component={PaymentScreen} />
<Stack.Screen name="Lawn Care" component={LawnCareScreen} />
<Stack.Screen name="Reset Password" component={ResetPasswordScreen} />
<Stack.Screen name="Car Detail" component={CarDetailScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
To disable user from navigating back to the previous screen after logout you need to clear the stack of the stack navigator in the Product Screen . I have provided the code sample below
import { StackActions, NavigationActions } from "react-navigation";
export default function ProductScreen({ navigation }) {
const logOutPress = () => {
try {
auth()
.signOut()
.then(() => {
const resetAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: "Login" })],
});
navigation.dispatch(resetAction);
alert("You have signed out");
});
} catch (error) {
console.log("err", error);
}
};
return (
<TouchableOpacity onPress={() => logOutPress()}>
<Text style={styles.buttonText}>Log Out</Text>
</TouchableOpacity>
);
}
i use this code in the index.js to logout :
<Stack.Screen name="Main" component={Main} options={({ navigation,route }) => ({
title: '', headerLeft: () => (<TouchableOpacity onPress={() => (_singout())}
style={{ margin: 16, marginTop: Platform.OS == 'ios' ? StatusBar.currentHeight : 0 }}>
<Image resizeMode="contain" source={mylogoutImage} style={{ marginTop: 20 }} />
</TouchableOpacity>),
})} />
and in _singout() function clear my asyncStorage.
I hope to help you.
I ve got nested navigation, and I would like to hide a header bar from a single page from my bottom tab navigation(I am doing this because I want to have a different color ). So I managed to do that by creating the SleepStackScreen component and give the header the color that I want, but now I am having two headers, one from the TabScreen component and one from the SleppStackScreen.
Any hint of how could I hide the TabScreen header only on SleepStackScreen.
I already tried with options={{ headerShown: false}} but no luck.
The green header on the first picture i want to keep it on existing pages, whereas on the second picture I want to remove it and to keep the blue one
const SleepStackScreen = ({navigation}) => (
<SleepStack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: '#1f65ff',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}>
<SleepStack.Screen
name="Sleep"
component={Sleep}
options={({navigation, route}) => ({
headerTitle: (props) => <Header {...props} />,
})}
/>
</SleepStack.Navigator>
);
const TabsScreen = () => (
<Tabs.Navigator shifting={true} initialRouteName="Home" activeColor="#fff">
<Tabs.Screen
name="Home"
component={Browser}
options={{
name: 'sal',
tabBarLabel: 'Home',
tabBarColor: '#009387',
tabBarIcon: ({color}) => (
<MaterialCommunityIcons name="home" color={color} size={26} />
),
}}
/>
<Tabs.Screen
name="Sleep"
component={SleepStackScreen}
options={{
tabBarLabel: 'Sleep',
title: 'sal',
tabBarColor: '#694fad',
tabBarIcon: ({color}) => (
<MaterialCommunityIcons name="sleep" color={color} size={26} />
),
}}
/>
<Tabs.Screen
name="Settings"
component={SettingWithContext}
options={{
tabBarLabel: 'Settings',
tabBarColor: '#009387',
tabBarIcon: ({color}) => (
<MaterialCommunityIcons name="settings" color={color} size={26} />
),
}}
/>
</Tabs.Navigator>
);
export default CreateStack = () => {
const [isLoading, setIsLoading] = React.useState(true);
const [userToken, setUserToken] = React.useState(null);
const authContext = React.useMemo(() => {
return {
signIn: () => {
setIsLoading(false);
setUserToken('asdf');
},
signUp: () => {
setIsLoading(false);
setUserToken('asdf');
},
signOut: () => {
setIsLoading(false);
setUserToken(null);
},
};
}, []);
React.useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 1000);
}, []);
if (isLoading) {
return <LoadingScreen />;
}
return (
<AuthContext.Provider value={authContext}>
<NavigationContainer>
{userToken ? (
<Stack.Navigator
initialRouteName={Browser}
screenOptions={{
//headerShown: false,
headerStyle: {
backgroundColor: '#009387',
},
headerTintColor: '#fff',
}}>
<Stack.Screen
name="Browser"
component={TabsScreen}
options={({route}) => ({
headerTitle: getHeaderTitle(route),
})}
options={({navigation, route}) => ({
headerTitle: (props) => <Header {...props} />,
})}
/>
<Stack.Screen
name="PreScreen"
component={PreScreen}
options={({navigation, route}) => ({
headerTitle: (props) => <Header {...props} />,
})}
/>
<Stack.Screen
name="PreScreenSleep"
component={PreScreenSleep}
options={({navigation, route}) => ({
headerTitle: (props) => <Header {...props} />,
headerStyle: {
backgroundColor: '#694fad',
},
})}
/>
<Stack.Screen
name="Player"
component={Player}
options={({navigation, route}) => ({
headerTitle: (props) => <Header {...props} />,
})}
/>
</Stack.Navigator>
) : (
<AuthStack.Navigator initialRouteName={RegisterLogin}>
<AuthStack.Screen
name="RegisterLogin"
component={RegisterLogin}
options={({navigation, route}) => ({
headerTitle: (props) => <Header {...props} />,
headerStyle: {
backgroundColor: '#f4511e',
},
})}
/>
<AuthStack.Screen
name="Login"
component={LoginWithContext}
options={({navigation, route}) => ({
headerTitle: (props) => <Header {...props} />,
})}
/>
<AuthStack.Screen
name="Register"
component={RegisterWithContext}
options={({navigation, route}) => ({
headerTitle: (props) => <Header {...props} />,
})}
/>
</AuthStack.Navigator>
)}
</NavigationContainer>
</AuthContext.Provider>
);
UPDATE as of version 5
As of version 5 it is the option headerShown in screenOptions
Example of usage:
<SleepStack.Navigator
screenOptions={{
headerShown: false
}}
>
<SleepStack.Screen
name="Sleep"
component={Sleep}
options={({navigation, route}) => ({
headerTitle: (props) => <Header {...props} />,
})}
/>
</SleepStack.Navigator>
ok try this
<SleepStack.Navigator
screenOptions={({ route }) => {
let shown = true;
if (route.state.routeNames[route.state.index] === "Sleep") {
shown = false;
}
return {
headerShown: shown
};
}}>
<SleepStack.Screen
name="Sleep"
component={Sleep}
options={({navigation, route}) => ({
headerTitle: (props) => <Header {...props} />,
})}
/>
</SleepStack.Navigator>;