Update tabBarLabel based on state in React Native - javascript

I have a React Native app with a Navigator. I also have a few screens and a header (common to all screens).
In my header I have a button that toggles the app's language. Passing the language to the Navigator's props I'm able to access it in the screens and translate stuff around.
The only thing I can't change is the tabBarLabel property in the navigationOptions of each screen.
I've tried to simply write:
MyStack1.navigationOptions = {
tabBarLabel: myGlobalTranslationFunction('MyOriginalLabel1', this.props.screenProps.language)
};
But that didn't work.
As a tree, you can think of App being the root of my app, which has a state.language passed to the Navigator by:
<Navigator screenProps={ {language: this.state.language} }/>
In my Navigator.js file, I have, for example:
const MyStack1 = createStackNavigator({
MyScreen1: MyScreenComponent1,
MyScreen2: MyScreenComponent2,
MyScreen3: MyScreenComponent3,
});
MyStack1.navigationOptions = {
tabBarLabel: 'MyLabel1'
};
export default createBottomTabNavigator({
MyStack1,
MyStack2
},
{
initialRouteName: 'MyStack1',
tabBarOptions: {
showLabel: true
}
}
);
I think this problem lies in defining that the labels depend on the language prop, but I don't know how to do that. I thought about writing an actual class that extends React.Component for the Navigator, but I'm not sure how someone who do that, since the code above was basically the one I got by following the documentation.

What's react-navigation version you are using?
You can pass down the translations through screenProps of the Navigator.
<Navigator screenProps={{
myStack1: i18n._('stack1TabBarLabel'),
myStack2: i18n._('stack2TabBarLabel')
}}/>
And modify how createBottomTabNavigator create the component.
export default createBottomTabNavigator({
myStack1: {
screen: MyStack1,
navigationOptions: ({ screenProps }) => ({
tabBarLabel: screenProps && screenProps.myStack1
})
},
myStack2: {
screen: MyStack2,
navigationOptions: ({ screenProps }) => ({
tabBarLabel: screenProps && screenProps.myStack2
})
}
},
{
initialRouteName: 'myStack1',
tabBarOptions: {
showLabel: true
}
}
);

Related

React Native Passing Props through Nested Navigators

Hi I was wonder how I could pass props down the navigators or if there's a better way of designing my structure.
const MangaTabRouter = createMaterialTopTabNavigator(
{
Info: { screen: Manga },
Chapter: { screen: Chapter }
}
);
const Stack = createStackNavigator(
{
Main: {
screen: MangaTabRouter,
navigationOptions: {
header: props => <CustomHeader {...props} />
}
}
}
);
const HomeScreenRouter = createDrawerNavigator(
{
MyLibrary: { screen: HomeScreen },
Sources: { screen: Sources },
Manga: { screen: Stack }
},
{
contentComponent: props => <SideBar {...props} />,
initialRouteName: "MyLibrary"
}
);
const AppContainer = createAppContainer(HomeScreenRouter);
I then have a button that calls the Main URI and goes there as well as passing in some props.
this.props.navigation.navigate('Main', {data});
Currently, I use dangerouslyGetParent() to access the props but I find it not appropriate for my design and also it doesn't work with multiple Manga entries (ie. props don't change). I would ideally like to pass props (the data object) to both the Info and Chapter URIs under the tab navigator. I assume it has to do with passing props to the router itself? So my question is: is it possible to send props to sub children as well or would I have to somehow redesign my routers to pass in a component to Main that then has MangaTabRouter as a child component within it? Also, is there a way to pass the props that I sent to Info to the header as well? I'm experimenting but coming up empty handed. Thanks!
const MangaTabRouter = createMaterialTopTabNavigator(
{
Info: { screen: props => <Manga {...props}/> },
Chapter: { screen: props => <Chapter {...props}/> }
}
);
class ExtendStack extends React.Component {
static router = MangaTabRouter.router;
render() {
const { navigation } = this.props;
return <MangaTabRouter navigation={navigation} screenProps={navigation.state.params} />;
}
}
const Stack = createStackNavigator(
{
Main: {
screen: ExtendStack,
navigationOptions: {
header: props => <CustomHeader {...props} />
}
}
}
);
I had to use screenProps to pass in the new information. I'll take a closer look at the header and try with a similar approach.
you need to pass the data as item: this.props.navigation.navigate('Main', {data : item})
and call this.props.navigation.state.params.data in your child component

how to hide back button in React-navigation/react-native

I would like to hide the Back button in the top-left corner, but I don't have any idea how to do it with react-navigation or react-native.
Just tried to use static navigationOptions = { header: null } but the < Back button was still alive.
I was using Modal and it works, but I want to know how to hide < Back button without using Modal.
Thank you in advance!
Using headerLeft: () => <></> works great in iOS, but in Android was still displaying the default back button.
I was able to hide it by adding the headerBackVisible: false on the screenOptions of the Stack Navigator or you could include it on the options for every Stack Screen.
More info at https://reactnavigation.org/docs/native-stack-navigator/#headerbackvisible
I suppose you're using a StackNavigator and that you don't want a header.
You need to use headerMode: none in the StackNavigatorConfig.
For example:
const ModalStack = createStackNavigator(
{
HomeScreen: { screen: Home },
ModalScreen: { screen: Modal },
},
{
headerMode: 'none',
mode: 'modal',
}
);
More info in the react-navigation docs.
It depends upon the react navigation version you're using, try this
const ModalStack = createStackNavigator(
{
HomeScreen: { screen: Home },
ModalScreen: { screen: Modal },
},
{
headerMode: 'none',
header: null
}
);
if it is StackNavigator default config, go to StackNavigator:
defaultNavigationOptions: {
header: null,
},
const Stack = createStackNavigator();
<Stack.Navigator screenOptions={{headerShown: false}}>
createStackNavigator is a function that returns an object containing 2 properties: Screen and Navigator. Both of them are React components used for configuring the navigator.
Now below Stack.Navigator, you can place your screens using <Stack.Screen name="Home" component={HomeScreen} />. In name, you can give any name, and in component give the name of your component.

Error when defining a state on navigation options

I am trying to use a library to enable localization. In the sample app when I click on a button, I get an error:
Unhandled JS Exception: `title` cannot be defined as a function in navigation options for `Settings` screen.
Try replacing the following:
{
title: ({ state }) => state...
}
with:
({ navigation }) => ({
title: navigation.state...
})
I am not sure when the problem is, but I think it´s on this peace of code
const AppNavigator = StackNavigator({
Home: {
screen: WelcomeContainer,
navigationOptions: {
title: 'Multi Language Sample App' // we advice using something static like your app's name or company name on the startup screen
}
},
Settings: {
screen: SettingsContainer,
navigationOptions: {
title: (navigation) => {
return navigation.state.params.title
}
}
},
About:{
screen: About,
navigationOptions: {
title: (navigation) => {
return navigation.state.params.title
}
}
}
})
I tried to replace the code with the proposed one but it didn't worked. Can you help me solving the problem?
react-navigation StackNavigator title prop expects a string value.
title
String that can be used as a fallback for headerTitle. Additionally, will be used as a fallback for tabBarLabel (if nested in
a TabNavigator) or drawerLabel (if nested in a DrawerNavigator)
If you want to set title dynamically you can try to implement below code.
Settings: {
screen: SettingsContainer,
navigationOptions: ({navigation}) => ({
title: navigation.state.params.title
})
}

DrawerItems not showing from StackNavigator (react-navigation)

Currently Im trying to make a drawer using react-navigation.
my react-navigation version is : "^1.0.0-beta.7"
Basically my structure of react-navigation look like this
StackNavigator as the root..
DrawerNavigator as the 2nd layer..
and another StackNavigator as the 3rd layer..
My problem is that when I put my component inside DrawerNavigator, The Component header will not show up after navigate to the component.. So, Im hoping anyone who can pointed to me how to make header visible when I put my component inside DrawerNavigator. If I did not put any component inside DrawerNavigator and all the screen inside the inner StackNavigator, the header will be visible but then the DrawerItems doesnt have any props thus not showing inside the drawer.
const rootNav = StackNavigator({
MainDrawerNavigator: { screen: MainDrawerNavigator }
}, {
headerMode: 'screen',
navigationOptions: { header: null }
})
const MainDrawerNavigator = DrawerNavigator({
Home: { screen: HomeNavigator },
Logout: { screen: Logout }
},{
initialRouteName: 'Home',
drawerWidth: 270,
headerMode: 'screen',
contentComponent: (props) => {
return(
<ScrollView>
<DrawerItems {...props} />
</ScrollView>
)
},
contentOptions: {
style: {
marginTop: 0,
}
}
})
const HomeNavigator = StackNavigator({
HomeMenu: { screen: HomeMenu },
StartJourney: { screen : StartJourney },
JournalList: { screen: JournalList },
)}
Hope anyone can help me with this.
Thanks!
I'm trying to achieve where DrawerOpen the header will not show
I don' understand which header here is?
but when I navigate the route from Drawer and it open a screen, then
the header will show up
If you're talking about navigator header, it's header of HomeNavigator, you can do like you did with rootNav navigationOptions: { header: null }
const HomeNavigator = StackNavigator({
HomeMenu: { screen: HomeMenu },
StartJourney: { screen : StartJourney },
JournalList: { screen: JournalList },
},{
navigationOptions: { header: null }
})
And current react-navigation document is for beta.9 / beta.10 I don't know if these props work on beta.7. There are some big changes on style and props from beta.7 to beta.8

react native navigate with different files

As a newbie in react-native i'm trying find a way to use react-navigation with different files without a navbar to navigate (for example just click on a button in the login view to enter the main view, clicking on log out button return to login view).
With react-navigation i made a global component 'Nav' and i placed in the main AppRegistry call:
AppRegistry.registerComponent('myApp', () => Nav);
While in the Navigator.js:
export const Nav = StackNavigator({
Login: { screen: LoginView },
AddStream: { screen: AddStreamView },
});
When i run
react-native run-android
i get the first view loaded under a white space (it should be the navigator, that i don't want in my app)
Now how can i remove the Nav from the view and how can i change View onPress a button component in another file?
There is another package that fill better my desire?
From the docs, setting the the headerMode to none should do the trick. This will hide the header on all of the screens defined in that StackNavigator. Example:
const Nav = StackNavigator({
Login: { screen: LoginView },
AddStream: { screen: AddStreamView },
},{
headerMode: 'none',
});
If you want to control the visibility of the header so that it appears on some of the screens but not all of them, then you can set headerMode to screen and for each individual screen set [the navigation prop for header: { visible: false }. See docs here. For example, if you are creating the screen component in another file, it might look like this:
// In the main file:
const Nav = StackNavigator({
Login: { screen: LoginView },
AddStream: { screen: AddStreamView },
},{
headerMode: 'screen',
});
// Hidden for your Login screen:
export default class LoginView extends Component {
static navigationOptions = {
header: { visible: false }
}
// etc...
}
// Visible for your AddStream screen:
export default class AddStreamView extends Component {
static navigationOptions = {
header: { visible: true }
}
// etc...
}
Edit: missed the second part of your question.
For navigating to a different screen, you really should go through the Hello World tutorial as it explains it. Specifically, this section. Relevant example code from the tutorial:
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Text>Hello, Chat App!</Text>
<Button
onPress={() => navigate('Chat')}
title="Chat with Lucy"
/>
</View>
);
}
In your case, 'Chat' would be either 'Login' or 'AddStream'.

Categories