How to avoid the suddenly chop down on react native navigator - react-native

Here is the code I got:
I got a Stack Navigator that store two screens:
<Stack.Navigator
initialRouteName="FirstScreen"
screenOptions={{
headerShown: false
}}>
<Stack.Screen name="FirstScreen" component={FirstScreen}/>
<Stack.Screen name="DrawerNavigator" component={DrawerNavigator}/>
</Stack.Navigator>
And I got a DrawerNavigator which have my MainNavigator, which is the screen cap I provided:
<Drawer.Navigator
initialRouteName="MainNav"
screenOptions={{
drawerStyle: {
backgroundColor: getPrimaryColor()
},
drawerLabelStyle: {
color: 'white'
}
}}>
<Drawer.Screen
name="MainNav"
component={MainNav}
options={({route}) => (getShowOptions(route))}/>
</Drawer.Navigator>
Inside the MainNav, it have two page, one is home, another is detail:
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
options={{ headerShown:false }}
name="Home"
component={Home}
/>
<Stack.Screen
name="Detail"
component={Detail} />
</Stack.Navigator>
As you may noticed that it has a getShowOptions method, which is control the actual nav bar display:
function getShowOptions(route) {
const routeName = getFocusedRouteNameFromRoute(route);
const icon =
let options = {
headerStyle: {
backgroundColor: getPrimaryColor()
},
headerTintColor: '#fff',
headerTitleAlign: 'center',
title: i18n.t('Home'),
drawerIcon: ({focused, size}) => (
<View
style={[{
height: iconSize,
width: iconSize
}
]}>
{icon}
</View>
)
};
if (routeName === 'Detail') {
options.headerShown = false;
}
return options;
}
When the screen is push to "Detail", it will hide the header, to show a header that have a back button, but when it put back to "Home", it should use back the "Drawer" menu button. As u can see the issue happen when we switch back and forward between the drawer navigation bar and the stack navigation bar.
The use case is pretty simple, we would like to have the "menu" when the "home" screen is appear, and "back" appear when the "detail" screen is presented. It seems that the React Native Stack Navigator and Drawer Navigator can't work together very well. Any suggestions?

Related

How to disable black shadow in react native navigation?

I try to set the background of a card to transparent, but somehow a black shadow remains. How do I remove the the shadow?
const screenOptions = useMemo<StackNavigationOptions>(
() => ({
...TransitionPresets.SlideFromRightIOS,
safeAreaInsets: { top: 0 },
// presentation: "modal",
cardStyle: {
backgroundColor: "transparent",
},
cardShadowEnabled: false,
}),
[]
);
const screenAOptions = useMemo(() => ({ headerShown: false }), []);
return (
<NavigationContainer independent={true}>
<Stack.Navigator
screenOptions={{ headerShown: false }}
headerMode="screen"
>
<Stack.Screen
name="Home"
options={screenOptions}
component={() => <View style={{ flex: 1 }} />}
/>
</Stack.Navigator>
</NavigationContainer>
As a site note: The Navigator is located in a bottom drawer. However, the shadow appears only with the Navigator and not with other components located directly in the bottom drawer. Thats why i think its related to the navigator.

React native : bottom navigation with dynamic initialRouteName implementation

I am a beginner in react native. I have gone through different related topics. But failed. This is my issues,
I have a bottom navigator with 4 items, say Dashboard, X, Patient and Y. Here is the optimised bottom navigator code.
const Stack = createStackNavigator();
const Bottom = createBottomTabNavigator();
const Main = () => {
return (
<Bottom.Navigator
initialRouteName="DashboardScreenStack"
tabBarOptions={{
style: {
height: 70,
paddingTop: 20,
backgroundColor: '#F3F6FF',
},
activeTintColor: colors.navigationTextActive,
inactiveTintColor: colors.navigationTextInactive,
labelStyle: {
fontSize: 15,
marginTop: 15,
paddingBottom: 10,
},
}}>
<Bottom.Screen
name="DashboardScreenStack"
component={DashboardScreenStack}
options={{
tabBarLabel: 'Dashboard',
}}
/>
<Bottom.Screen
name="X"
component={X}
options={{
tabBarLabel: 'X',
}}
/>
<Bottom.Screen
name="Patient"
component={Patient}
options={{
tabBarLabel: 'Patient',
}}
/>
<Bottom.Screen
name="Y"
component={Y}
options={{
tabBarLabel: 'Y',
}}
/>
</Bottom.Navigator>
);
};
This is my code for Patient menu.
const Patient = (props) => {
let resultData = null;
var initialRoute = '';
if (
typeof props.route.params != 'undefined' &&
props.route.params.result != null
) {
resultData = props.route.params.result;
initialRoute = 'PatientDashboardScreen';
} else {
initialRoute = 'AddPatientScreen';
}
return (
<Stack.Navigator
initialRouteName={initialRoute }>
<Stack.Screen
name="PatientDashboardScreen"
component={PatientDashboardScreen}
initialParams={resultData}
options={{headerShown: false}}
/>
<Stack.Screen
name="TestScreen1"
component={TestScreen1}
options={{headerShown: false}}
/>
<Stack.Screen
name="TestScreen2"
component={TestScreen2}
options={{headerShown: false}}
/>
<Stack.Screen
name="AddPatientScreen"
component={AddPatientScreen}
options={{headerShown: false}}
/>
</Stack.Navigator>
);
};
There are 4 screens that should be shown in Patient menu. Out of those if I am selecting an item in my Dashboard menu I need to open "PatientDashboardScreen". And there will be some data available in props too. But on directly clicking 'Patient' menu, I need to move to "AddPatientScreen" where no data is passed.
I tried the above code. But only the initial click works. If I am selecting from list first, the always Patient menu is showing "PatientDashboardScreen" and if I am selecting Patient menu directly first, then always "AddPatientScreen" is shown on Patient menu selection.
Any help would be greateful. Thank you
Based on your question
You have a bottom navigator and one of the screens has a nested stack navigator.
The requirement here is to show a specific screen when pressing the bottom navigator button and redirect to a screen when opening from another screen in bottom navigator along with some parameters.
This is one way to do this.
<Tab.Screen
name="Hospital"
component={HospitalView}
options={({ navigation }) => ({
tabBarButton: (props) => (
<TouchableOpacity
{...props}
onPress={() =>
navigation.navigate('Hospital', { screen: 'Patient' })
}
/>
),
})}
/>
You can have a custom onPress in your bottom navigator button which will use the navigate with the screen option which will take you to the specific screen.
To navigate from another screen with parameters you can use the below option
<Button
title="Doctor"
onPress={() =>
navigation.navigate('Hospital', {
screen: 'Doctor',
params: { name: 'Doc 1' },
})
}
/>
Your full code should look something similar to this
const Stack = createStackNavigator();
function Patient() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Patient Screen</Text>
</View>
);
}
function Doctor({route}) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Doctor Screen</Text>
<Text>{route?.params?.name}</Text>
</View>
);
}
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
<Button
title="Doctor"
onPress={() =>
navigation.navigate('Hospital', {
screen: 'Doctor',
params: { name: 'Doc 1' },
})
}
/>
</View>
);
}
function HospitalView() {
return (
<Stack.Navigator>
<Stack.Screen name="Doctor" component={Doctor} />
<Stack.Screen name="Patient" component={Patient} />
</Stack.Navigator>
);
}
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen
name="Hospital"
component={HospitalView}
options={({ navigation }) => ({
tabBarButton: (props) => (
<TouchableOpacity
{...props}
onPress={() =>
navigation.navigate('Hospital', { screen: 'Patient' })
}
/>
),
})}
/>
</Tab.Navigator>
);
}
You can refer this sample
https://snack.expo.io/#guruparan/5f3f1d

'focus' listener not calling every time. React Native

I am new in react native technology. I have used following hierarchy in my react native app.
I have used Stack.Navigator in which I am using various screen, I. Login, II. Sign-Up, III. TabBar Screen.
In TabBar screen I have used various individual Stack.Navigator because I have to show tab bar on every child screen.
Now problem is that I have to update some value on tab screen when user click on that particular screen. It is calling once at first time, not working second time.
I have used following code for execute 'focus' listener on tab screen :-
onScreenFocus = () => {
this.reloadFavrouite()
alert("again calling")
}
componentDidMount() {
this.props.navigation.addListener('focus', () => this.onScreenFocus())
this.reloadFavrouite()
}
'focus' listener work well If I am not use individual Stack.Navigator at every tab screen, but it is creating another issue is that tab bar not showing in child screen.
I have used this tab navigator code:- Please check
export default class TabNavigator extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<Tab.Navigator initialRouteName='Home' lazy={true} tabBarOptions={
{
style: {
backgroundColor: '#FFFFFF',
borderTopLeftRadius: 25,
borderTopRightRadius: 25,
overflow: 'hidden',
borderColor: 'transparent',
}
}
}>
<Tab.Screen name="HomeNavigator" component={HomeNavigator}
options={{
tabBarLabel: ({ focused }) => {
const tintColortab = focused ? "#006C35"
: "#000000"
return (
<Text style={{ color: tintColortab, fontSize: 8, fontFamily: "Roboto-Bold", marginBottom: 6 }}>{StringsOfLanguages.Home}</Text>
)
},
tabBarIcon: ({ focused }) => {
const tintColortab = focused ? "#006C35"
: "#000000"
return (
<Image source={require('../../../assets/images/TabBarIcons/ic_home_selected/ic_home_selected.png')}
style={{ marginTop: 10, tintColor: tintColortab }}>
</Image>
)
}
}}>
</Tab.Screen>
<Tab.Screen name="FavouriteNavigator" component={FavouriteNavigator}
options={{
tabBarLabel: ({ focused }) => {
const tintColortab = focused ? "#006C35"
: "#000000"
return (
<Text style={{ color: tintColortab, fontSize: 8, fontFamily: "Roboto-Bold", marginBottom: 6 }}>{StringsOfLanguages.Favorite}</Text>
)
},
tabBarIcon: ({ focused }) => {
const tintColortab = focused ? "#006C35"
: "#000000"
return (
<Image source={require('../../../assets/images/TabBarIcons/ic_favorits_unselected/ic_favorite_unselected.png')}
style={{ marginTop: 10, tintColor: tintColortab }}>
</Image>
)
}
}}
>
</Tab.Screen>
</Tab.Navigator>
);
}
And individual navigation is like :-
class HomeNavigator extends React.Component {
render() {
return (
<NavigationContainer independent={true}>
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} options={{ headerShown: false }} />
<Stack.Screen name="AllRestuarent" component={AllRestuarent} options={{ headerShown: false }} />
<Stack.Screen name="AllLaundry" component={AllLaundry} options={{ headerShown: false }} />
<Stack.Screen name="AllEntertainment" component={AllEntertainment} options={{ headerShown: false }} />
<Stack.Screen name="Offer" component={Offer} options={{ headerShown: false }} />
<Stack.Screen name="ComponyMap" component={ComponyMap} options={{ headerShown: false }} />
</Stack.Navigator>
</NavigationContainer>
);
}
}
class FavouriteNavigator extends React.Component {
render() {
return (
<NavigationContainer independent={true}>
<Stack.Navigator>
<Stack.Screen name="Favorites" component={Favorites} options={{ headerShown: false }} />
<Stack.Screen name="Offer" component={Offer} options={{ headerShown: false }} />
<Stack.Screen name="ComponyMap" component={ComponyMap} options={{ headerShown: false }} />
</Stack.Navigator>
</NavigationContainer>
);
}
}
You are not using focus listener in the right way according to your current version, You are using react-navigation v5 and you are adding a listener the way it is used in react-navigation v4, Here is a solution to your problem.
class YourClassComopnent extends React.Component {
componentDidMount() {
/*
Now you can access to isFocused prop and
this prop will be true whenever your screen is
in the focus.
*/
if(this.props.isFocused) this.onScreenFocus()
this.reloadFavrouite()
}
render() {
// Get it from props
const { isFocused } = this.props;
}
}
// Wrap and export
export default function(props) {
const isFocused = useIsFocused();
// pass your class here
return <YourClassComopnent {...props} isFocused={isFocused} />;
}
Link to docs, how you can use isFocused in react-navigation v5

How to navigate to a another screen in class component in react native

App.js code:
function firstScreenStack({ navigation }) {
return (
<Stack.Navigator initialRouteName="Login">
<Stack.Screen
name="Login"
component={Login}
options={{
title: 'Login', //Set Header Title
headerLeft: ()=>
<NavigationDrawerStructure
navigationProps={navigation}
/>,
headerStyle: {
backgroundColor: '#CA2C68', //Set Header color
},
headerTintColor: '#fff', //Set Header text color
headerTitleStyle: {
fontWeight: 'bold', //Set Header text style
},
}}
/>
</Stack.Navigator>
);
}
function secondScreenStack({ navigation }) {
return (
<Stack.Navigator
initialRouteName="Browse"
screenOptions={{
headerLeft: ()=>
<NavigationDrawerStructure
navigationProps={navigation}
/>,
headerStyle: {
backgroundColor: '#CA2C68', //Set Header color
},
headerTintColor: '#fff', //Set Header text color
headerTitleStyle: {
fontWeight: 'bold', //Set Header text style
}
}}>
<Stack.Screen
name="Browse"
component={Browse}
options={{
title: 'Browse', //Set Header Title
}}/>
<Stack.Screen
name="Profile"
component={Profile}
options={{
title: 'Profile', //Set Header Title
}}/>
</Stack.Navigator>
);
}
export default App function has below code:
<NavigationContainer>
<Drawer.Navigator
initialRouteName = {Login}
drawerContentOptions={{
activeTintColor: '#CA2C68',
itemStyle: { marginVertical: 5 },
}}>
<Drawer.Screen
name="Login"
options={{ drawerLabel: 'Login' }}
component={firstScreenStack} />
<Drawer.Screen
name="Browse"
options={{ drawerLabel: 'Browse' }}
component={secondScreenStack} />
<Drawer.Screen
name="Profile"
options={{ drawerLabel: 'Profile' }}
component={profileScreenStack} />
</Drawer.Navigator>
</NavigationContainer>
I am using stack and drawer navigation both.
I want navigation.navigate("Profile");
Now how can I get navigation props into my class components? I am new in react native and navigation. Its bit complicated to understand for me. If you can help me out it will be better. Thanks.
If we are supposed to navigate from the screen of the first stack navigator to another navigator then we have to access the parent of the first navigator's screen, which mean we have to get the navigation prop of the first stack navigator as we have created a drawer based on the multiple screens.
fox ex. if you want to navigate from the Browse screen of firstScreenStack to another drawer screen navigator then have a try with the below code:
if using Class Component:
this.props.navigation.dangerouslyGetParent()?.navigate("<<ANOTHER_DRAWER_SCREEN>>")
if using Functional Component:
props.navigation.dangerouslyGetParent()?.navigate("<<ANOTHER_DRAWER_SCREEN>>")
Navigation is accessible in stack routes only i.e, those classes or components which are used as routes in different navigators.
Now if i got your question, you want to access it in all components irrespective of whether it is a route or not. You can do that by passing props to it from a component which is a route.
E.g,
Let main be a route and child be another component but not a route.
Inside the main;
<child new_navigation={this.props.navigation} />
Now you can access the new_navigation inside the child.
Inside the child;
this.props.new_navigation.navigate('some_route') //you can now use all the other methods also like push, replace etc.

How to update header bar from drawer screen

I am using nested navigation. The root navigator is a StackNavigator and child is DrawerNavigator as far as I know there is no way to put a header bar via DrawerNavigator.
So I made it via StackNavigator but I can not update the header title when I navigate a screen that in the DrawerNavigator. How can I update header title in a DrawerScreen
Root Navigator:
<Stack.Navigator screenOptions={screenOptions} initialRouteName="Login">
<Stack.Screen name="Login" component={Login} />
// ...
<Stack.Screen // This is the screen that contains a child navigator
name="Main"
component={Main}
options={({navigation}) => ({
title: 'Main Page',
headerLeft: () => <MenuIcon stackNavigation={navigation} />,
})}
/>
</Stack.Navigator>
Child Navigator:
<Drawer.Navigator>
//...
<Drawer.Screen
name="Bids"
component={Bids}
options={{
title: text.bids, // This updates the title that in the drawer navigator menu not the header bar title.
headerTitle: () => <SearchBar />, //Also this doesn't work I can not update header bar specific to a DrawerComponent.
}}
/>
//...
</Drawer.Navigator>
I try to pass navigation prop of Stack Screen to Drawer Screens but I could not find any way to do this.
<Drawer.Screen
component={<Bids stackNavigation={navigation} />} // This does not compile :(
//...
/>
I try to use setOptions:
const Bids = ({navigation}) => {
navigation.setOptions({title: 'Bids'});
//...
};
But again it updates the title in the drawer menu not the Header Bar title.
How can I update Header Bar from a Drawer Screen?
I am able to get it. I have the following setup.
First -> A Stack = Pre-Home + Home tabs
Second -> Bottom tabs
Third -> Stack for individual tabs, lets call it inner stack
So, i have a Stack <-> Bottom Tabs <-> Inner Stack.
On Screen change of inner stack, i need to update header which is part of my Parent Stack/Root Stack.
This can be done with the following in the Parent Stack. In your root/Parent Stack have the below
<Stack.Screen
name="Tabs"
component={MyTabs}
options={({ route, navigation }) => {
let currStackState = [];
let currScreenName = null;
if (route.state) {
currStackState = route.state.routes[route.state.index].state;
const currIndex = currStackState.index;
currScreenName = (currStackState.routes[currIndex]).name;
}
let headerForScreen = getHeaderForRoute(currScreenName);
// further common things if you want to add can add to above object headerForScreen
return headerForScreen;
}}
/>
your function to header can look like this
const getHeaderForRoute = (routeName, stackName) => {
//just kept stackName for future purpose, not using it.
switch (routeName) {
case 'Scree1':
case 'MoreScreens':
case '':
return {
headerShown: true,
headerStyle: DeviceInfo.hasNotch()
? [styles1.headerBGColor, styles1.withNotch] : styles1.headerBGColor,
headerTitle: '',
headerLeft: () =>
// Reactotron.log("route", route);
(
<View style={{
flex: 1, marginLeft: 18, flexDirection: 'row',
}}
>
{/* your component */}
</View>
),
headerRight: () => (
<View style={{ marginRight: 15, flexDirection: 'row' }}>
{/* your code*/}
</View>
),
};
case 'SomeOther':
return {
headerShown: true,
headerTitle: 'SomeTitle'
};
default:
return {};
}
};