How to create different top tabs in multiple screens in React Native - react-native

I am looking to create different tabs in different screens. This is a little hard to explain so i will post a couple photos to illustrate my desire output.
I've already created a tab navigator using createMaterialTopTabNavigator, but it seems like i can't apply the same logic twice in a whole separate js file. My javascript is fairly weak.
This is my code for the first tab navigation(newsfeed + services). I am looking to do the exact same thing except with different tab titles.
My question is, how would i go about achieving my desire output?
import {createMaterialTopTabNavigator} from 'react-navigation';
import NewsfeedActivity from './NewsfeedActivity';
import ServiceActivity from './ServiceActivity';
export default createMaterialTopTabNavigator({
Newsfeed:{screen: NewsfeedActivity},
Services:{screen:ServiceActivity}
},
{
initialRouteName:'Services',
swipeEnabled:true,
navigationOptions:({navigation})=>({
header:null
}),
tabBarOptions:{
activeTintColor:'#65FAE9',
inactiveTintColor:'white',
allowFontScaling:true,
indicatorStyle:{borderBottomColor:'#65FAE9', borderBottomWidth:4,},
style:{backgroundColor:'#515276',paddingBottom:5},
labelStyle:{fontWeight:'bold',marginTop:'40%'},
},
},
);
What i have:
What Im looking to create:

You can nest multiple navigators.
If your desired output is to have the bottom navigation different in "Newsfeed" and different in "Services" , then instead of passing a page as the screen , you can pass a bottomNavigator
import {createMaterialTopTabNavigator,createBottomTabNavigator} from 'react-navigation';
import NewsfeedActivity from './NewsfeedActivity';
import ServiceActivity from './ServiceActivity';
export default createMaterialTopTabNavigator({
Newsfeed:{screen: firstBottomNavigation},
Services:{screen: secondBottomNavigation }
},
{
initialRouteName:'Services',
swipeEnabled:true,
navigationOptions:({navigation})=>({
header:null
}),
tabBarOptions:{
activeTintColor:'#65FAE9',
inactiveTintColor:'white',
allowFontScaling:true,
indicatorStyle:{borderBottomColor:'#65FAE9', borderBottomWidth:4,},
style:{backgroundColor:'#515276',paddingBottom:5},
labelStyle:{fontWeight:'bold',marginTop:'40%'},
},
},
);
const firstBottomNavigation = createBottomTabNavigator({
FirstTab:{screen FirstTab},
SecondTab: {screen:SecondTab}
})
const secondBottomNavigation = createBottomTabNavigator({
ThirdTab:{screen ThirdTab},
SecondTab: {screen:SecondTab} //You can recycle screens
})
You can get creative , you can try nesting a toptabnavigator in a bottomnavigator ,etc . But don't make things too complicated because if it's complicated for you, imagine how hard is gonna be for the user

Related

How to wrapper createStackNavigator with redux?

I think my question is clear. Before I start, I should show about the project structure I created myself.
I added the router logic to the project later and I think it will work better.
stack_main.js following;
import Screen from '../screens';
import {createStackNavigator} from 'react-navigation-stack';
export default createStackNavigator(
{
HomeScreen: Screen.HomeScreen,
MyEarningsScreen: Screen.MyEarningsScreen,
// TestScreen: Screen.TestScreen,
},
{
cardStyle: {
backgroundColor: '#000000',
},
},
);
In fact, if you can change the value of "cardStyle.backgroundColor" in any way, there is no need to wrap it with redux. Since redux is state management, I can't wrap the createStackNavigator function in the react-navigation module or I don't know.
I need to change the "cardStyle.backgroundColor" value every time a stack is pushed. How can I do it ?
Thank you for interest.
Why do I want this?
I created a side menu using react-native-drawer as in the image below.
In the module I used, no matter what I gave the offset props value, there were white parts of the background color; As a result of my research as a solution to this cardStyle I saw and applied.
Update to the latest version of react-navigation-stack and then use screenProps customize the colors dynamically.

i18n translation for "Back"-text in React Navigation on iOS

I'm using React Navigation and a StackNavigator in a React Native app. I'm able to translate the navigationOptions.title, however, on iOS if there is too much text in the header it defaults to showing the text "Back" next to the back button. I don't mind this, but I want it to say "Back" in my current language. How can I achieve this? The text I'm talking about:
An example of how I use the navigationOptions now:
class Example extends Component<Props> {
static navigationOptions = () => ({
title: i18n.t('example_title'),
});
// ...
}
In case it is relevant we're using react-native-localize with i18n-js for the i18n functionality. I don't want it to always say the previous screens name, or always back, I want it dynamically as it is now, just with i18n.
The navigationOptions object has an key for this called headerTruncatedBackTitle.
Title string used by the back button when headerBackTitle doesn't fit on the screen. "Back" by default. headerTruncatedBackTitle has to be defined in the origin screen, not in the destination screen.
You can for example utilize this with i18n simply by doing:
class Example extends Component<Props> {
static navigationOptions = () => ({
title: i18n.t('example_title'),
headerTruncatedBackTitle: i18n.t('example_back'), // "Back", "Zurück", etc.
});
// ...
}
In my application in Main AppStack createStackNavigator where you combine all of your screens, I have added a second parameter an object in which we give it a key
createStackNavigator({
...screens
},
{
defaultNavigationOptions: {
headerBackTitle: i18n.t('example_title')
}
})
This will set the Back button to the current language of the entire application.

Why Navigation.goBack() not working properly?

I am using following way to create navigation system
StackNavigator -> DrawerNavigator -> (Screen A, Screen B, Screen C)
Screen A is initial Route
Screen A to Screen B Using
this.props.navigation.navigate("Screen B") //Working Fine
Screen B to Screen C Using
this.props.navigation.navigate("Screen C") //Working Fine
In Screen C
this.props.navigation.goBack() //Not Working
But
this.props.navigation.goBack(null) //It's going to Screen A instead of Screen B
What's wrong here.
Please help me Thank you.
As you didn't show the navigation structure of the drawer, I don't know how the 3 screens are put inside of it. I'm assuming they are 3 different drawerScreens
This happens because you are using a DrawerNavigation, that doesn't create a history of screens when you navigate around it.
To solve this you have to change the navigation structure to something like:
DrawerNavigation => StackNavigator => Screen A, B, C
You can specify backBehavior="history" inside Drawer.Navigator and it shouldn't move you to the initial root on goBack anymore :)
Example:
<Drawer.Navigator
backBehavior="history"
>
...
As the answer above is, the drawer navigators are not in the stack, so you can't tell the path of your journey.
the key property for goBack() is a dynamically created string, created by react-navigation whenever navigate to a new route.
These stack keys are stored in this.props.navigation.state
NOTE: Use .goBack(null) if your goal is to return to any place
without specifying a closing target.
Like this example, you can add to the stack.
Example
const Drawers = createDrawerNavigator(
{
A: {
screen: HomeScreen
},
...
},
{
initialRouteName: "A"
}
);
const RootStack = createStackNavigator(
{
Drawers: {
screen: Drawers
},
otherStack: {
screen: otherStack
},
....

MaterialTopTabNavigator dynamic route configs

I want to create via createBottomTabNavigator. It has 5 tabs. Each tab is a StackNavigator.
One of these tabs has a top tab bar. I create the top tab bar via createMaterialTopTabNavigator
But I know tab count after http request. How can I add tab dynamically? The doc says that
There are workarounds if you absolutely need dynamic routes but you can expect some additional complexity
I am confused about this task.
How can I do that?
Related react-navigation issue: https://react-navigation.canny.io/feature-requests/p/dynamic-routes-for-navigators
I think you can create a component that returns a tabNavigator. You can then access props or do whatever you want to dynamically add or remove tabs. Here I am using the latest version of react-navigation.
import React, { Component } from 'react-native';
import { createAppContainer, createMaterialTopTabNavigator } from 'react-navigation';
class DynamicTabs extends Component {
render() {
// I am using a prop here to update the Tabs but you can use state to update
// when the network request has succeeded or failed
const { shouldRenderTab } = this.props;
const TabNavigator = createMaterialTopTabNavigator({
Tab1: Tab1Component,
Tab2: Tab2Component,
// Create a tab here that will display conditionally
...(shouldRenderTab ? { Tab3: Tab3Component } : {}),
});
const ContainedTabNavigator = createAppContainer(TabNavigator);
return <ContainedTabNavigator />;
}
}
export default DynamicTabs;
This is the current solution I am using adapted from the original solution posted on github

React Navigation cache component

I am fairly new to React Native and a little confused with the following. I've set up a StackNavigator as shown
const MyProjectNavigator = StackNavigator({
home: {screen: Other},
latest_news: {screen: LatestNews}
}
When I want to go to a different screenm the navigation I perform is:
navigate(
latest_news, {
otherParams : param1
}
);
This works well so far.
Now, assume that the latest_news component queries a lot of data from a server when mounted, then performs lots of operations on that data, sorting by date, author, yadda yadda. This takes some time to complete.
How would you suggest I made this faster? On iOS for example i would normally keep my ViewController in memory and if it was available, display that. When using navigate(), the navigator seems to create a new instance of the component thus reloading and re-processing everything from the beginning making the users wait every time.
*TL;DR
I want to keep all the data my component has queried and processed across navigation so that the processing doesn't have to repeat constantly.
I could just put the data on the global object but that doesn't sound like a good solution
Thanks a bunch.
You can use the TabNavigator instead of the StackNavigator.
TabNavigators reuse the same instances of its route items.
you can disable the visibility of the TabBar:
const TabNav = TabNavigator({
Home: { screen: HomePage},
NewsFeed1: { screen: NewsFeed} ,
NewsFeed2: { screen: NewsFeed} ,
NewsFeed3: { screen: NewsFeed} ,
// ...
},
{
navigationOptions: ({ navigation }) => ({
tabBarVisible: false,
}),});
and then you can navigate manually - for example with a button:
<Button title="NewsFeed1" onPress={() => this.props.navigation.navigate("NewsFeed1") }/>
Have a look at a simple example:
https://github.com/chrisdie/AwesomeNavigation/blob/master/src/tabbar2/App.js