How to navigate to a screen in parent navigation in React native - javascript

I am very new to React Navigation and am trying to implement the following functionality in react-native:
I have a stack navigator as a parent and a bottom navigation bar as its child. From the home screen, when the user clicks the logout option, they should return to the Sign In screen which is a part of the parent navigation.
There are already a lot of questions regarding this, but I am not able to implement the previous solutions in my code.
Someone please help me out, the code is given below (This is an Expo managed project):
Navigation Components
import { NavigationContainer } from "#react-navigation/native";
import { createNativeStackNavigator } from "#react-navigation/native-stack";
import WelcomeScreen from "../screens/WelcomeScreen";
import Features from "../screens/Features";
import SignIn from "../screens/SignIn";
import Register from "../screens/Register";
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import { Icon } from "react-native-elements";
import Home from "../screens/Home";
import Reminders from "../screens/Reminders";
import Settings from "../screens/Settings";
const BottomNavbar = () => {
const Tab = createBottomTabNavigator();
return (
<Tab.Navigator
initialRouteName="Home"
screenOptions={({ route }) => ({
tabBarIcon: ({ focused }) => {
let iconName;
let rn = route.name;
if (rn === "Home") {
iconName = focused ? "home" : "home-outline";
} else if (rn === "Reminders") {
iconName = focused ? "list" : "list-outline";
} else if (rn === "Settings") {
iconName = focused ? "settings" : "settings-outline";
}
return (
<Icon
name={iconName}
size={25}
color="black"
type="ionicon"
/>
);
},
})}
showLabel
>
<Tab.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
<Tab.Screen
name="Reminders"
component={Reminders}
options={{ headerShown: false }}
/>
<Tab.Screen
name="Settings"
component={Settings}
options={{ headerShown: false }}
/>
</Tab.Navigator>
);
};
const Navigator = () => {
const Stack = createNativeStackNavigator();
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{ headerShown: false }}
initialRouteName="Welcome"
>
<Stack.Screen name="Welcome" component={WelcomeScreen} />
<Stack.Screen name="Features" component={Features} />
<Stack.Screen name="SignIn" component={SignIn} />
<Stack.Screen name="Register" component={Register} />
<Stack.Screen name="BottomNavbar" component={BottomNavbar} />
</Stack.Navigator>
</NavigationContainer>
);
};
export default Navigator;
Home Screen Components
import {
View,
Text,
SafeAreaView,
StyleSheet,
TouchableOpacity,
ScrollView,
} from "react-native";
import React from "react";
import { Header, Image, Icon } from "react-native-elements";
import { useFonts } from "expo-font";
import ServiceCard from "../components/ServiceCard";
import PetCard from "../components/PetCard";
const SignOut = ({ navigation }) => {
return (
<TouchableOpacity
onPress={() => {
navigation.navigate("SignIn");
}}
>
<Icon name="logout" color="black" size={20} />
</TouchableOpacity>
);
};
const Home = () => {
const [loaded, error] = useFonts({
Montserrat: require("../assets/fonts/Montserrat-Regular.ttf"),
});
if (!loaded) {
return null;
}
const url1 =
"https://images.unsplash.com/photo-1530281700549-e82e7bf110d6?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=388&q=80";
const url2 =
"https://images.unsplash.com/photo-1560807707-8cc77767d783?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=435&q=80";
const url3 =
"https://images.unsplash.com/photo-1543466835-00a7907e9de1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=774&q=80";
return (
<View style={styles.screen}>
<Header
leftComponent={{
icon: "menu",
color: "black",
}}
rightComponent={<SignOut />}
centerComponent={{
text: "PetPapa",
color: "black",
style: {
fontFamily: "Montserrat",
fontSize: 20,
},
}}
barStyle="dark-content"
backgroundColor="white"
containerStyle={styles.header}
/>
<View style={styles.community}>
<View style={styles.commOffer}>
<View>
<Text style={styles.commOfferTitle}>Join our</Text>
<Text style={styles.commOfferTitle}>
community today!
</Text>
</View>
<TouchableOpacity style={styles.btn}>
<Text style={styles.commOfferJoin}>Join Now</Text>
</TouchableOpacity>
</View>
<Image
source={{
uri: "https://imgur.com/nB4Xm1Z.png",
}}
style={styles.commDog}
/>
</View>
<View style={styles.listView}>
<View style={styles.topText}>
<Text style={styles.title}>Services</Text>
<TouchableOpacity>
<Text style={styles.option}>See more</Text>
</TouchableOpacity>
</View>
<ServiceCard />
</View>
<View style={styles.listView}>
<View style={styles.topText}>
<Text style={styles.title}>My Pets</Text>
<TouchableOpacity>
<Text style={styles.option}>See all</Text>
</TouchableOpacity>
</View>
<ScrollView
style={styles.petView}
horizontal={true}
showsHorizontalScrollIndicator={true}
persistentScrollbar={true}
>
<PetCard name="Miles" Img={url1} />
<PetCard name="Jack" Img={url2} />
<PetCard name="Ellie" Img={url3} />
</ScrollView>
</View>
</View>
);
};
const styles = StyleSheet.create({
screen: {
height: "100%",
backgroundColor: "white",
alignItems: "center",
},
header: {
backgroundColor: "white",
height: 80,
},
community: {
backgroundColor: "#1976D2",
height: "15%",
width: "80%",
borderRadius: 20,
marginTop: 50,
flexDirection: "row",
justifyContent: "space-around",
},
commDog: {
marginTop: 10,
marginRight: 15,
height: 105,
width: 75,
},
commOffer: {
marginTop: 10,
flexDirection: "column",
justifyContent: "space-around",
},
commOfferTitle: {
color: "white",
fontFamily: "Montserrat",
fontSize: 16,
},
btn: {
backgroundColor: "#FFC107",
width: "50%",
borderRadius: 10,
},
commOfferJoin: {
color: "white",
margin: 5,
},
listView: {
marginTop: 50,
width: "80%",
},
topText: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
},
title: {
fontFamily: "Montserrat",
fontWeight: "600",
},
option: {
fontFamily: "Montserrat",
opacity: 0.4,
},
block: {
backgroundColor: "#FF5677",
width: 75,
height: 100,
justifyContent: "center",
alignItems: "center",
marginTop: 25,
borderRadius: 20,
},
petView: {
width: "100%",
backgroundColor: "white",
height: 250,
},
});
export default Home;
My Directory Structure:

First you need to add navigation prop to Home screen component
const Home = ({navigation}) => {
const [loaded, error] = useFonts({
Montserrat: require("../assets/fonts/Montserrat-Regular.ttf"),
});
...
then You need to pass navigation prop to the signout component
<Header
leftComponent={{
icon: "menu",
color: "black",
}}
rightComponent={<SignOut navigation={navigation} />}
...
You can also use useNavigation hook from react navigation
import { useNavigation } from '#react-navigation/native';
const SignOut = ({}) => {
const navigation = useNavigation()
return (
<TouchableOpacity
onPress={() => {
navigation.navigate("SignIn");
}}
>
<Icon name="logout" color="black" size={20} />
</TouchableOpacity>
);
};
If You want to create login flow then you should use Authentication flow which I think best prectice and recommended way
The problem in current flow if you logout and navigate to sign-in page once then if you navigate back from you app then as behaviour of stack navigation it just pop current screen and it will again navigate to home screen which is not what supposed to be correct.
You can learn it from react-navigation offical doc
https://reactnavigation.org/docs/auth-flow/
if you want a video tutorial how to implement Authentication flow using redux(state management lib) then I have video tutorial you can learn this video -> https://youtu.be/cm1oJ7JmW6c

Related

tabBarOptions not applied to project (React Native)

I am creating a small app that has a to-do list and a calendar. At the bottom is a bottom tab navigator. Everything works and is functional, however, when I try to add style: {} inside tabBarOptions it isn't being applied. Changing activeTintColor, inactiveTintColor and labelStyle works just fine.
I tried to create a stylesheet and replace everything inside tabBarOptions, but that didn't work. My main goal is to simply create a slightly larger bar along the bottom of the screen. I don't even want a crazy custom navigation bar, just slightly larger so I can make the items inside a little bigger.
MainContainer Class:
import React from 'react';
import {StyleSheet} from 'react-native';
import {NavigationContainer} from '#react-navigation/native';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import Ionicons from 'react-native-vector-icons/Ionicons'
//screens
import Calendar from './screens/Calendar';
import ToDoList from './screens/ToDoList';
// Screen names
const calendarName = 'Calendar';
const ToDoListName = 'To Do List';
const Tab = createBottomTabNavigator();
export default function MainContainer() {
return (
<NavigationContainer>
<Tab.Navigator
tabBarOptions={{
activeTintColor: 'tomato',
inactiveTintColor: 'black',
labelStyle: {paddingBottom: 10, fontSize: 10},
style: {padding: 10, height: 70},
}}
initialRouteName={ToDoListName}
screenOptions={({route}) => ({
tabBarIcon: ({focused, color, size}) => {
let iconName;
let rn = route.name;
if (rn === ToDoListName) {
iconName = focused ? 'list' : 'list-outline'; //icons in package. Change later.
} else if (rn === calendarName) {
iconName = focused ? 'calendar' : 'calendar-outline'
}
return <Ionicons name={iconName} size={size} color={color}/>
},
})}>
<Tab.Screen name={ToDoListName} component={ToDoList}/>
<Tab.Screen name={calendarName} component={Calendar}/>
</Tab.Navigator>
</NavigationContainer>
)
}
For reference here is my ToDoList class
import { KeyboardAvoidingView, StyleSheet, Text, View, TextInput, TouchableOpacity, Platform, Keyboard } from 'react-native';
import Task from '../../components/Task';
import React, { useState } from 'react';
import { ScrollView } from 'react-native-web';
export default function ToDoList() {
const [task, setTask] = useState();
const [taskItems, setTaskItems] = useState([]);
const handleAddTask = () => {
Keyboard.dismiss();
setTaskItems([...taskItems, task])
setTask(null);
}
const completeTask = (index) => {
let itemsCopy = [...taskItems];
itemsCopy.splice(index, 1);
setTaskItems(itemsCopy)
}
return (
<View style={styles.container}>
{/* Scroll View when list gets longer than page */}
<ScrollView contentContainerStyle={{
flexGrow: 1
}} keyboardShouldPersistTaps='handled'>
{/*Today's Tasks */}
<View style={styles.tasksWrapper}>
<Text style={styles.sectionTitle}>Today's Tasks</Text>
<View style={styles.items}>
{/* This is where the tasks will go*/}
{
taskItems.map((item, index) => {
return (
<TouchableOpacity key={index} onPress={() => completeTask(index)}>
<Task text={item} />
</TouchableOpacity>
)
})
}
</View>
</View>
</ScrollView>
{/* Write a task section */}
{/* Uses a keyboard avoiding view which ensures the keyboard does not cover the items on screen */}
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style={styles.writeTaskWrapper}>
<TextInput style={styles.input} placeholder={'Write a task'} value={task} onChangeText={text => setTask(text)} />
<TouchableOpacity onPress={() => handleAddTask()}>
<View style={styles.addWrapper}>
<Text style={styles.addText}>+</Text>
</View>
</TouchableOpacity>
</KeyboardAvoidingView>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#E8EAED',
},
tasksWrapper: {
paddingTop: 20,
paddingHorizontal: 20,
},
sectionTitle: {
fontSize: 24,
fontWeight: 'bold',
},
items: {
marginTop: 30,
},
writeTaskWrapper: {
position: 'absolute',
bottom: 20,
paddingLeft: 10,
paddingRight: 10,
width: '100%',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center'
},
input: {
paddingVertical: 15,
width: 250,
paddingHorizontal: 15,
backgroundColor: '#FFF',
borderRadius: 60,
borderColor: '#C0C0C0',
borderWidth: 1,
},
addWrapper: {
width: 60,
height: 60,
backgroundColor: '#FFF',
borderRadius: 60,
justifyContent: 'center',
alignItems: 'center',
borderColor: '#C0C0C0',
borderWidth: 1,
},
addText: {
},
});
And my Calendar class
import * as React from 'react';
import { View, Text } from 'react-native';
export default function Calendar(){
return(
<View>
<Text>Calendar Will go here</Text>
</View>
)
}
I made a Task component for the ToDoList. Not sure if you need it to solve this but I'll paste it here anyway.
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { TouchableOpacity } from 'react-native-web';
const Task = (props) => {
return (
<View style={styles.item}>
<View style={styles.itemLeft}>
<View style={styles.square}></View>
<Text style={styles.itemText}>{props.text}</Text>
</View>
<View style={styles.circular}></View>
</View>
)
}
const styles = StyleSheet.create({
item: {
backgroundColor: '#FFF',
padding: 15,
borderRadius: 10,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 20,
},
itemLeft: {
flexDirection: 'row',
alignItems: 'center',
flexWrap: 'wrap',
},
square: {
width: 24,
height: 24,
backgroundColor: '#55BCF6',
opacity: .4,
borderRadius: 5,
marginRight: 15,
},
itemText: {
maxWidth: '80%',
},
circular: {
width: 12,
height: 12,
borderColor: '#55BCF6',
borderWidth: 2,
borderRadius: 5
},
});
export default Task;
It sounds like you are looking for the tabBarStyle property. You should be able to rename style (which is not a supported prop of the tab navigator) to tabBarStyle.
Here's the spot in the docs that mentions this. https://reactnavigation.org/docs/bottom-tab-navigator#tabbarstyle
What I ended up doing to solve this was to put the styling inside the screenOptions. I didn't want to do this because I wanted to separate the styling from the logic, but it solved the problem for me. See code below:
export default function MainContainer() {
return (
<NavigationContainer>
<Tab.Navigator
initialRouteName={ToDoListName}
screenOptions={({route}) => ({
tabBarIcon: ({focused, color, size}) => {
let iconName;
let rn = route.name;
if (rn === ToDoListName) {
iconName = focused ? 'list' : 'list-outline'; //icons in package. Change later.
} else if (rn === calendarName) {
iconName = focused ? 'calendar' : 'calendar-outline'
}
return <Ionicons name={iconName} size={size} color={color}/>
},
activeTintColor: 'tomato',
inactiveTintColor: 'black',
tabBarShowLabel: false,
tabBarStyle: {padding: 10, height: 100, backgroundColor: 'black'},
})}>
<Tab.Screen name={ToDoListName} component={ToDoList}/>
<Tab.Screen name={calendarName} component={Calendar}/>
</Tab.Navigator>
</NavigationContainer>
)
}

React Native : onPress not working for authentification

I'm transitionning from React to React Native, and so far got the basics. In my application I'm trying to implement the authentification.
I already setup my working APIs for the login and registration and verified them using POSTMAN.
The problem here is for some reason onPress={onSignInHandler} doesn't do anything. Normally in React I would put onClick={onSignInHandler} and everything will be working fine.
I would like, when the Login is pressed, execute the axios request, and then redirect to for example "Myprofil.js" component or atleast display and alert to see if it's working. As far as I know React Native uses react-navigation instead of react-router.
app.js:
import * as React from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import Login from './src/views/Login';
import Signup from './src/views/Signup ';
import MyProfil from './src/views/MyProfil';
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Login" screenOptions={{
headerShown: false
}}>
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="Signup " component={Signup} />
<Stack.Screen name="MyProfil" component={MyProfil} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
login.js :
import React, { Component, UseState } from 'react';
import { View, Text, TextInput, StyleSheet, Image, Dimensions, Alert } from 'react-native';
import axios from "axios";
const { width, height } = Dimensions.get('window');
function Login() {
const [state, setState] = React.useState({
msg: "",
isLoading: false,
redirect: false,
errMsgEmail: "",
errMsgPwd: "",
errMsg: "",
});
const [email, setEmail] = React.useState("");
const [password, setPassword] = React.useState("");
const handleChangeEmail = (event) => {
setEmail(event.target.value);
};
const handleChangePassword = (event) => {
setPassword(event.target.value);
};
function onSignInHandler() {
const infos = {
email: email,
password: password,
};
axios
.post("http://127.0.0.1:8000/api/login", infos)
.then((response) => {
if (response.data.status === 200) {
localStorage.setItem("isLoggedIn", true);
localStorage.setItem("userData", JSON.stringify(response.data.data));
this.setState({
msg: response.data.message,
redirect: true,
});
}
if (
response.data.status === "failed" &&
response.data.success === undefined
) {
this.setState({
errMsgEmail: response.data.validation_error.email,
errMsgPwd: response.data.validation_error.password,
});
setTimeout(() => {
this.setState({ errMsgEmail: "", errMsgPwd: "" });
}, 2000);
} else if (
response.data.status === "failed" &&
response.data.success === false
) {
this.setState({
errMsg: response.data.message,
});
setTimeout(() => {
this.setState({ errMsg: "" });
}, 2000);
}
})
.catch((error) => {
console.log(error);
});
};
return (
<View
style={{
flex: 1,
backgroundColor: 'white',
justifyContent: 'flex-end'
}}
>
<View style={{ ...StyleSheet.absoluteFill }}>
<Image
source={require('../images/bg.jpg')}
style={{ flex: 1, height: null, width: null }}
>
</Image>
</View>
<View style={{ height: height / 2, justifyContent: 'center' }}>
<View>
<Text style={{ fontSize: 20, fontWeight: 'bold', color:"#ffffff",fontSize: 30, marginHorizontal: 40,marginVertical: 10, }}>Bienvenue !</Text>
</View>
<View style={styles.button}>
<TextInput placeholder="E-mail " style={{ fontSize: 20, fontWeight: 'bold' }} value={email} onChange={handleChangeEmail}></TextInput>
</View>
<View style={styles.button}>
<TextInput placeholder="Password" style={{ fontSize: 20, fontWeight: 'bold' }} secureTextEntry={true} value={password} onChange={handleChangePassword}></TextInput>
</View>
<View style={{alignItems: 'center',justifyContent: 'center', marginTop: 20}}>
<Text style={{ fontSize: 20, fontWeight: 'bold', color: '#ffffff' }} onPress={onSignInHandler}>
LOGIN
</Text>
</View>
</View>
</View>
);
}
export default Login;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
button: {
backgroundColor: 'white',
height: 50,
marginHorizontal: 30,
borderRadius: 35,
alignItems: 'center',
justifyContent: 'center',
marginVertical: 10,
}
});
Instead of using onPress for Text component wrap it with a TouchableOpacity and use the onPress of the TouchableOpacity
<TouchableOpacity onPress={onSignInHandler}>
<Text style={{ fontSize: 20, fontWeight: 'bold', color: '#ffffff' }} title="Profil" >LOGIN</Text>
</TouchableOpacity>
Change your
function onSignInHandler() {
to
const onSignInHandler = () => {

Improving React Native performance deactivating Component when not in use

I'm developing an app for tuning pianos in react-native. I have an App.js and some screens implemented with react-navigation. The question is, how i can deactivate (or just not render) a component Screen when the user isn't in that screen?
The idea is to catch when this Screen Component is the Active Screen (like using navigation props), i can activate the render and deactivate when the Active Screen changes.
The Tab.js, containing the tab screens.
import React from "react";
/** Screens */
import TunerScreen from "./tunerScreen";
import Inharmonicity from "./inharmonicityScreen";
import BeatsScreen from "./beatsScreen";
/** Navigation */
import { MaterialCommunityIcons } from "#expo/vector-icons";
import { createMaterialBottomTabNavigator } from "#react-navigation/material-bottom-tabs";
/** Tab */
const Tab = createMaterialBottomTabNavigator();
/* Tabs of screen */
export default Tabs = ({
handleSwitch,
beatsCalc,
inharmonicityCalc,
inharmonicitySave,
}) => {
return (
<Tab.Navigator activeColor="#000" barStyle={{ backgroundColor: "white" }}>
<Tab.Screen
...
/>
// This is the component screen trying to deactivate
<Tab.Screen
name="Beats"
children={() => (
<BeatsScreen beatsCalc={beatsCalc} />
)}
options={{
tabBarLabel: "Beats",
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons
name="blur-radial"
color="black"
size={26}
/>
),
}}
/>
<Tab.Screen
...
/>
</Tab.Navigator>
);
};
The BeatsScreen.js (component to deactivate).
import React, { Component, useState } from "react";
import { View, Text, Button, Switch } from "react-native";
import Note from "../src/components/note";
import { connect } from "react-redux";
import style from "../styles/style";
import Picker from "#gregfrench/react-native-wheel-picker";
var PickerItem = Picker.Item;
class BeatsScreen extends Component {
constructor(props) {
super(props);
this.state = {
beats: 0,
// Prima nota
firstNote: { name: "A", octave: 4, frequency: 440, selected: false },
// Seconda nota
secondNote: { name: "A", octave: 4, frequency: 440, selected: false },
// Elemento selezionato dal picker
selectedItem: 0,
// Elementi del picker
itemList: ["Terza", "Quarta", "Quinta", "Ottava", "Prima"],
};
}
beatsUpdate = () => {
this.state.beats = beatsCalc(
this.state.firstNote,
this.state.secondNote,
this.state.selectedItem
);
};
render() {
if (!this.state.firstNote.selected)
this.state.firstNote = this.props.note;
if (!this.state.secondNote.selected)
this.state.secondNote = this.props.note;
this.beatsUpdate();
return (
<View style={{ flex: 1, flexDirection: "column" }}>
<View style={{ flex: 1 }}>
<View style={{ flex: 1, flexDirection: "row" }}>
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Note {...this.state.firstNote} />
<Text style={style.frequency}>
{this.state.firstNote.frequency.toFixed(1)} Hz
</Text>
{
<Switch
style={{
paddingTop: 50,
transform: [{ scaleX: 2 }, { scaleY: 2 }],
}}
value={this.state.firstNote.selected}
onValueChange={() => {
// Se la nota è stata selezionata
this.state.firstNote.selected =
!this.state.firstNote.selected;
}}
/>
}
</View>
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Note {...this.state.secondNote} />
<Text style={style.frequency}>
{this.state.secondNote.frequency.toFixed(1)} Hz
</Text>
<Switch
style={{
paddingTop: 50,
transform: [{ scaleX: 2 }, { scaleY: 2 }],
}}
value={this.state.secondNote.selected}
onValueChange={() => {
// Se la nota è stata selezionata
this.state.secondNote.selected =
!this.state.secondNote.selected;
}}
/>
</View>
</View>
</View>
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Picker
style={{ width: 150, height: 180 }}
lineColor="#000000" //to set top and bottom line color (Without gradients)
lineGradientColorFrom="#008000" //to set top and bottom starting gradient line color
lineGradientColorTo="#FF5733" //to set top and bottom ending gradient
selectedValue={this.state.selectedItem}
itemStyle={{ color: "black", fontSize: 26 }}
onValueChange={(index) => {
this.state.selectedItem = index;
this.beatsUpdate();
}}
>
{this.state.itemList.map((value, i) => (
<PickerItem label={value} value={i} key={i} />
))}
</Picker>
<Text style={{ fontSize: 18 }}>Battimenti: </Text>
<Text style={{ fontSize: 80, paddingTop: 1 }}>
{this.state.beats}
</Text>
</View>
</View>
);
}
}
/** Mappa lo stato (store) con le props, cosi' da poterle usare nel componente. */
const mapStateToProps = (state) => {
const { note } = state;
const { tunerSwitch } = state;
return { note, tunerSwitch };
};
const mapDispatchToProps = (dispatch) => {
return {
startAndStop: () => dispatch({ type: "SWITCH" }),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(BeatsScreen);
I think if you use this option on the init of the tab bar you could solve your issue https://reactnavigation.org/docs/bottom-tab-navigator/#detachinactivescreens

React navigation 5 tabBarVisible not completely hidden

I added a button in tabBarIcon and it is not completely hidden when using tabBarVisible,my code:
file: App.js
i'm just added a different icon in AddScreen.
import HomeStack from './stacks/Home';
import UserStack from './stacks/User';
import AddStack from './stacks/Add';
import AddIcon from './AddIcon';
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen
name="Home"
component={HomeStack}
options={{
tabBarIcon: () => <IconAnt name={'home'} style={styles.icon} />,
}}
/>
<Tab.Screen
name="Add"
component={AddStack}
options={{
tabBarIcon: () => <AddIcon />, // icon add
title: '',
}}
/>
<Tab.Screen
name="User"
component={UserStack}
options={{
tabBarIcon: () => <IconAnt name={'user'} style={styles.icon} />,
}}
/>
</Tab.Navigator>
</NavigationContainer>
);
}
file: stacks/Home.js
when press 'go to detail', I'm hide the tabbar
function HomeScreen({navigation}) {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>Home!</Text>
<TouchableOpacity onPress={() => navigation.navigate('Detail')}>
<Text>go to detail/Text>
</TouchableOpacity>
</View>
);
}
function DetailScreen() {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>Detail!</Text>
</View>
);
}
const HomeStack = createStackNavigator();
export default function ({navigation, route}) {
var tabBarVisible = true;
if (typeof route.state !== 'undefined') {
const {routes} = route.state;
if (routes.length > 1) {
tabBarVisible = false;
}
}
navigation.setOptions({tabBarVisible});
// tabbar will hide when moving to Detail screen
return (
<HomeStack.Navigator>
<HomeStack.Screen name={'Home'} component={HomeScreen} />
<HomeStack.Screen name={'Detail'} component={DetailScreen} />
</HomeStack.Navigator>
);
}
AddIcon.js
file icon of AddScreen
export default function () {
return (
<View style={styles.container}>
<View style={styles.button}>
<IconAnt name={'plus'} style={{fontSize: 30, color: '#fff'}} />
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
position: 'absolute',
alignItems: 'center',
zIndex: 99,
},
button: {
alignItems: 'center',
justifyContent: 'center',
width: 72,
height: 72,
borderRadius: 72 / 2,
backgroundColor: 'red',
position: 'absolute',
marginTop: -45,
shadowColor: 'red',
shadowRadius: 5,
shadowOffset: {height: 10},
shadowOpacity: 0.3,
borderWidth: 2,
borderColor: '#FFFFFF',
zIndex: 99,
},
});
Screenshot:
Home screen
Detail screen
How do I hide it completely? Thanks!
Actually your tab bar is hiding but as you place this on above of the tabs that's why you still able to see after making tabBarVisible = false you also have to hide it manually with styles while making tabBarVisible = false, Check the route and apply styles dynamically.
pass style object to tabBarOptions
tabBarOptions: {
style: {
opacity: 0
}
}
Or this may also work
tabBarOptions: {
style: {
top: 50
}
}
Edit: By looking into your code I had to change some structure of your navigator and now it's working in the snack, You were rendering stack inside the tabs but it should be tabs inside a stack.
Link to snack
I just faced the same issue when I used the custom image.
Here is my solution.
You have to find the index of the Tab you want to hide. Then you can handle the opacity of the tab bar by checking the index.
tabBarOptions={{
style: {...styles.navigator, opacity: routeIndex === 2 ? 0 : 1},
}}
const HomeTab = createBottomTabNavigator();
export const HomeTabScreens = ({route}) => {
const routeIndex = route.state.index; // 2 is the screen that I want to hide.
...
}
you can add focused prop in tabBarIcon and apply style accordingly :
tabBarIcon: ({focused) => {
<Image
source={InstaCircleIcon}
style={[
{width: 87, height: 87},
focused && {width: 0, height: 87},
]}
/>
}
Complete example
<Tab.Screen
name="Addpost"
component={Addpost}
options={{
tabBarLabel: '',
tabBarIcon: ({focused}) => (
<TouchableOpacity style={[{top: -30, borderRadius: 50}]}>
<Image
source={InstaCircleIcon}
style={[
{width: 87, height: 87},
focused && {width: 0, height: 87},
]}
/>
</TouchableOpacity>
),
tabBarVisible: false,
}}
/>

React Navigation: Using single screen component in multiple tab navigation

I'm using createMaterialTopTabNavigator to create top tab navigation with two different tabs.
Each tab displays one image - either a Car or a Truck.
What I want to do is use a single screen component rather than the two-component screen (which I have right now). The picture of the tab screen displayed changes based on the active tab.
Is this possible in react-navigation 5.
This is what I have so far:
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createMaterialTopTabNavigator } from '#react-navigation/material-top-tabs';
function CarScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Image of car</Text>
</View>
);
}
function TruckScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Image of truck</Text>
</View>
);
}
const Tab = createMaterialTopTabNavigator();
function MyTabs() {
return (
<Tab.Navigator
initialRouteName="Car"
>
<Tab.Screen
name="Car"
component={FeedScreen}
options={{ tabBarLabel: 'Car' }}
/>
<Tab.Screen
name="Truck"
component={NotificationsScreen}
options={{ tabBarLabel: 'Truck' }}
/>
</Tab.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<MyTabs />
</NavigationContainer>
);
}
You can access the route name by using props.route.name and you can change image by using that condition.
I also made a snack here: https://snack.expo.io/#gie3d/shallow-blueberries
function CarOrTruck({route}) {
const getImageUrl = (routeName) => {
if (routeName === 'Car') {
return 'https://www.extremetech.com/wp-content/uploads/2019/12/SONATA-hero-option1-764A5360-edit.jpg'
} else if (routeName === 'Truck') {
return 'https://www.volvotrucks.com/content/dam/volvo/volvo-trucks/masters/press-releases/2020/feb/pr-2952-fh/high-res-08A3977-FH-4x2-semi-trailer-long-haul-on-road.jpg';
} else {
return 'https://brayve.net/wp-content/uploads/2019/06/4004/the-secret-history-of-the-google-logo.jpg-23keepProtocol'
}
}
const imageUrl = getImageUrl(route.name);
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Image source={{uri: imageUrl}} style={{width: 200, height: 100, resizeMode: 'contain'}} />
</View>
);
}
So in your 2 , it refers to component={CarOrTruck}
<Tab.Screen
name="Car"
component={CarOrTruck}
options={{ tabBarLabel: 'Car' }}
/>
<Tab.Screen
name="Truck"
component={CarOrTruck}
options={{ tabBarLabel: 'Truck' }}
/>

Categories

Resources