Passing props to Tab.Screen within BottomTabNavigator - react-native

I am running into difficulty passing props to one of my TabScreens using react-native's BottomTabNavigator. I have tried a couple of different options. Without props the Tab.Screen looks like this:
<Tab.Screen
name='Visits'
component={VisitsTab}
options={{
tabBarLabel: 'Visits',
tabBarIcon: ({ color, size }) => <FontAwesome name='street-view' color={color} size={size} />,
}}
/>
So what I tried was this:
<Tab.Screen
name='Visits'
component={(props) => <VisitsTab {...props} />}
options={{
tabBarLabel: 'Visits',
tabBarIcon: ({ color, size }) => <FontAwesome name='street-view' color={color} size={size} />,
}}
/>
This still doesn't work, as the prop I am logging out in the VisitsTab is undefined - in other words, the VisitsTab is not receiving props. And to clarify, props is available in the MainScreen that passed on the props. What am I missing here?
By the way, I also tried this, but get the same issue:
<Tab.Screen
name='Visits'
options={{
tabBarLabel: 'Visits',
tabBarIcon: ({ color, size }) => <FontAwesome name='street-view' color={color} size={size} />,
}}
>
{(props) => <VisitsTab {...props} />}
</Tab.Screen>
The full navigation for this bottom tab navigator looks like this:
import { VisitsTab } from './tabs/VisitsTab';
import { ChartTab } from './tabs/ChartTab';
import { GoalsTab } from './tabs/GoalsTab';
export const MainScreen = (props) => {
const Tab = createBottomTabNavigator();
return (
<Tab.Navigator
screenOptions={{
headerShown: true,
title: 'Patient',
headerLeft: () => (
<Feather
name='chevron-left'
size={24}
onPress={() => props.navigation.goBack()}
/>
),
}}
initialRouteName={'Visits'}
>
<Tab.Screen
name='Visits'
component={(props) => <VisitsTab {...props} />}
options={{
tabBarLabel: 'Visits',
tabBarIcon: ({ color, size }) => <FontAwesome name='street-view' color={color} size={size} />,
}}
/>
<Tab.Screen
name='Chart'
component={ChartTab}
options={{
tabBarLabel: 'Charts',
tabBarIcon: ({ color, size }) => <FontAwesome name='id-badge' color={color} size={size} />,
}}
/>
<Tab.Screen
name='Goals'
component={GoalsTab}
options={{
tabBarLabel: 'Edit Goals',
tabBarIcon: ({ color, size }) => <FontAwesome name='trophy' color={color} size={size} />,
}}
/>
</Tab.Navigator>
);
};
By the way, somewhat frustratingly, the documentation page for the Bottom Tabs Navigator doesn't actually address how to pass props.

Props for a component (for a screen to be precise) are not passed by the navigation framework. Props are passed from a parent to its child components. When writing component={Visits}, we do not instantiate an actual JSX components. Thus, there are no props to be passed.
In order to pass information during navigation, we use the route params. Here is an example: navigation.navigate("Visits", {x: 42}).
However, if Visits is supposed to be an initial screen of some navigator, then we have never actually navigated. Thus, the above approach does not help.
For this reason, the react-navigation framework added the initialParams prop for screens. They are defined inside the screen of some navigator.
<Tab.Screen
name='Visits'
component={VisitsTab}
initialParams={props}
/>
whereby props is any object and it might be better to use a different name, since these aren't actual props.
Then, access them in your screen.
function VisitsTab({route}) {
const params = route?.params
return (...)
}
We can access the passed information via params.

Related

react-native : stack navigation into tab navigation whitout showing it

So i have a bottom tab navigation into app.js with 3 tabs:
=> map
=> user
=> settings
<NavigationContainer>
<TabNav.Navigator initialRouteName='home'>
<TabNav.Screen name='home' component={Map} options={{
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="map-search-outline" color={color} size={30} style={style.iconStyle} />
), tabBarLabel: (null)
}} />
<TabNav.Screen name='user' component={User} options={{
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="card-account-details-outline" color={color} size={30} style={style.iconStyle} />
),tabBarLabel: (null)
}} />
<TabNav.Screen name='settings' component={Settings} options={{
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="set-square" color={color} size={30} style={style.iconStyle} />
), tabBarLabel: (null)
}} />
</TabNav.Navigator>
</NavigationContainer>
So I want to acces to a stack nav screen (report for exemple) anywhere into the children screens/components (a modal for exemple) of the map or the settings but not from the homescreen without showing it in the nav of the homescreen or the direct child of this homescreen, how can I do ?
In other words, I think I dont know where to write my hidden stack nav to be accessible from everywhere in the app. (but I understand how to pass it with the props)

React-navigation default drawer icon, how to change it?

How can I change the icon point in the image below? I have not been able to find the documentation in the docs, I would like to change it to a different icon but I have no idea how to do this.
I found documentation about drawerIcon but as far as I know and manage to implement that icon is for the menu items in the drawer it self not for the screen header.
Here is my code:
const Drawer = createDrawerNavigator();
const headerOptions = {
title: 'Task List',
drawerIcon: ({ focused, size, color }) => <Ionicons name="ios-pizza" color="red" size={24} />,
};
const HomeScreen = ({ navigation }, props) => {
return (
<Drawer.Navigator screenOptions={{ drawerType: 'front' }}>
<Drawer.Screen name="TaskList" component={TaskListScreen} options={headerOptions} />
<Drawer.Screen name="TaskView" component={TaskViewScreen} />
<Drawer.Screen name="Notifications" component={Notifications} />
<Drawer.Screen name="Login" component={LoginScreen} />
</Drawer.Navigator>
);
};
But as mention before it renders the icons in the drawer item as shown below
headerLeft: Function which returns a React Element to display on the left side of the header. You can use it to implement your custom left button, for example:
<Drawer.Navigator
screenOptions={({ navigation }) => ({
headerLeft: props => <IconComponent onPress={navigation.toggleDrawer} />,
})}
>
...
</Drawer.Navigator>
<Drawer.Navigator
screenOptions={{
headerTintColor: 'red', // -----> by changing color from here
}} drawerContent={props => <DrawerContent {...props} />} >
<Drawer.Screen />
</Drawer.Navigator >
you can also use a image as a drawer icon.
screenOptions={({ navigation }) => ({
headerLeft: () =>
<Pressable onPress={navigation.toggleDrawer}>
<Text>
<Avatar.Image size={32} source={{ uri: deafaultImage }} />
</Text>
</Pressable >
})}

React Native Tab Navigator

I am totally new to React Native and I am currently trying show BottomTabNavigator on child/details page, for example:
I have a page called Training and I have another page called TrainingDetails.
I wanna show BottomTabNavigator on TrainingDetails.
On truth, I wanna show BottomTabNavigator in all pages, main pages and detail pages.
Here is my Main.js
Thanks so much!
const Tab = createBottomTabNavigator();
return (
<Tab.Navigator tabBarOptions={{ activeTintColor: theme.colors.primary, inactiveTintColor: theme.colors.neutral_100, style: {backgroundColor: theme.colors.active} }}>
<Tab.Screen
options={{
title: "Trabalhar",
tabBarIcon: ({ focused, color, size }) => (
<MaterialIcon name={"headset"} size={size} color={color} />
),
}}
name="Home"
component={HomeScreen}
/>
<Tab.Screen
options={{
title: "Estudar",
tabBarIcon: ({ focused, color, size }) => (
<SimpleLineIcon name={"graduation"} size={size} color={color} />
),
}}
name="Study"
component={Training}
/>
<Tab.Screen
options={{
title: "Notificações",
tabBarIcon: ({ focused, color, size }) => (
<MaterialIcon name={"bell-outline"} size={size} color={color} />
),
}}
name="Notification"
component={HomeScreen}
/>
<Tab.Screen
options={{
title: "Resultados",
tabBarIcon: ({ focused, color, size }) => (
<MaterialIcon name={"trending-up"} size={size} color={color} />
),
}}
name="Results"
component={HomeScreen}
/>
<Tab.Screen
options={{
title: "Carteira",
tabBarIcon: ({ focused, color, size }) => (
<MaterialIcon name={"wallet-outline"} size={size} color={color} />
),
}}
name="Wallet"
component={HomeScreen}
/>
</Tab.Navigator>
);
};
export default Main;
You can put a stackNavigator inside a tab navigator, so for example if you want a home screen and then another screen called details that doesn't have a tab at the bottom but still has the tabs at the bottom you can replace the home screen with a homeStack that has both a home screen and details screen inside it.
const Stack = createStackNavigator();
function HomeStack() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Details" component={Details} />
</Stack.Navigator>
);
}
and then replace your home component in the tab navigator with HomeStack component.

How to send props from createBottomTabNavigation to every tab screen?

I am using createBottomTabNavigation and I have 4 screens which I can access by pressing the tab bar screen in the bottom of my screen. I am also using Stack Navigation to display the title of the screen there and also all screens have the same settings icon.
I could make the same function in every screen that takes care of onPress event on the Settings icon but that is repetitive and I don't want to do it.
My question is - is there a way for me to pass a function as a props from the App component which holds the bottom navigation to every screen?
App screen code:
<NavigationContainer >
<Tab.Navigator initialRouteName="Home" tabBarOptions={{
activeTintColor: '#FF9F0A',
inactiveTintColor:'white',
style: {
backgroundColor:'#000000',//color you want to change
borderTopWidth: 0,
paddingTop:5,
paddingBottom:5,
},
}}>
<Tab.Screen name="Home" component={Home} options={{
tabBarLabel: 'HOME',
tabBarIcon: ({ color, size }) => (
<HomeTabIcon name="home" color={color} size={size} />
),
}}/>
<Tab.Screen name="Controls" component={Controls} options={{
tabBarLabel: 'CONTROLS',
tabBarIcon: ({ color, size }) => (
<ControlsTabIcon name="controls" color={color} size={size} />
),
}}/>
<Tab.Screen name="Charging" component={Charging} options={{
tabBarLabel: 'CHARGING',
tabBarIcon: ({ color, size }) => (
<ChargingTabIcon name="charging" color={color} size={size}/>
),
}}/>
Charging screen:
function Charging() {
return (
<View style={globalStyles.container}>
<Text>Charging</Text>
<StatusBar style="auto" />
</View>
);
}
export default function ChargingStackScreen() {
return (
<ChargingStack.Navigator>
<ChargingStack.Screen name="CHARGING" component={Charging} options={{
headerRight: () => (
<View style={globalStyles.headerRight}>
<SettingsIcon />
</View>
),
headerTitleAlign:'left',
headerTintColor: 'white',
headerTitleStyle: globalStyles.headerTitle,
headerStyle: globalStyles.header
}}/>
</ChargingStack.Navigator>
);
}
So what I think you should do is have the header as a separate component, where you can use the useNavigation hook (assuming you're using the latest version of react-navigation), and have the settings button do the navigation you need. Then just render the header component once above the Tab.Navigator instead of rendering it on every screen.
Something like:
function Header(props){
const navigation = useNavigation();
// component code
<SettingsButton onPress={() => navigation.navigate(whatever)}/>
}
And then I am pretty sure (not 100% though) that you can render it in your NavigationContainer, something like:
<NavigationContainer >
<Header/>
<Tab.Navigator initialRouteName="Home" tabBarOptions={{
// rest of the code

react navigation tab screen icon color props type

I use eslint with vs code for my react native project .
I created a bottom tabs navigation using react navigation v5 :
...
<Tab.Screen
name="Contacts"
component={ContactStackScreen}
options={{
tabBarLabel: 'Contacts',
tabBarColor: COLORS.DEFAULT,
tabBarIcon: ({color}) => (
<MaterialCommunityIcons name="contacts" color={color} size={26} />
),
}}
...
I got eslint error for color props :
'color' is missing in props validation
I tried to fix it :
ButtomTabs.propTypes = {
color: PropTypes.string,
};
but i got this error :
propType "color" is not required, but has no corresponding defaultProps declaration
I believe there's a misunderstanding by the previous answers as to what is causing eslint to throw the react/prop-types error in this case. The lint error is correct - what's missing is the props validation for the arrow function introduced for tabBarIcon. Since that arrow function returns a React component, eslint is correct in enforcing the react/prop-types rule. To satisfy the rule, you need to provide prop types for that arrow function (think of the arrow function as an anonymous component which takes color as a prop). Just add {color: string} as the type definition for the entire parameter of that arrow function like this:
({color}: {color: string}) =>
In context:
<Tab.Screen
name="Contacts"
component={ContactStackScreen}
options={{
tabBarLabel: 'Contacts',
tabBarColor: COLORS.DEFAULT,
tabBarIcon: ({color}: {color: string}) => (
<MaterialCommunityIcons name="contacts" color={color} size={26} />
),
}}
Ignore the warning. It's a false positive.
tabBarIcon isn't a component and propTypes are only applicable to components
You're adding propTypes on BottomTabs component, but the warning is likely from the eslint plugin assuming that the function passed to tabBarIcon is a component
As per the documentation,
tabBarIcon is a supported option in bottom tab navigator. So we know we can use it on our screen components in the options prop, but in this case chose to put it in the screenOptions prop of Tab.Navigator in order to centralize the icon configuration for convenience.
here is an example of using Icon with Tab.Screen
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator
initialRouteName="Feed"
tabBarOptions={{
activeTintColor: '#e91e63',
}}
>
<Tab.Screen
name="Feed"
component={Feed}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="Notifications"
component={Notifications}
options={{
tabBarLabel: 'Updates',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="bell" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="Profile"
component={Profile}
options={{
tabBarLabel: 'Profile',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="account" color={color} size={size} />
),
}}
/>
</Tab.Navigator>
);
}