I want to change the label and the icon of React Navigation Tab bar based on Redux state. I don’t know how to access the state of Redux inside the AppNavigator.js. I usually use useSelector hook to do that, but this is not a component and I can’t do that here.
I want to change the label and the icon for the Profile dynamically.
Here is my code for the AppNavigator.js:
import React from "react";
import { Platform } from "react-native";
import { createAppContainer } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import { createBottomTabNavigator } from "react-navigation-tabs";
import { createMaterialBottomTabNavigator } from "react-navigation-material-bottom-tabs";
import { Ionicons } from "@expo/vector-icons";
import HomeScreen from "../screens/HomeScreen";
import ProductDetailsScreen from "../screens/ProductDetailsScreen";
import ProductsScreen from "../screens/ProductsScreen";
import CartScreen from "../screens/CartScreen";
import CategoriesListScreen from "../screens/CategoriesListScreen";
import OrdersListScreen from "../screens/OrdersListScreen";
import OrderDetailsScreen from "../screens/OrderDetailsScreen";
import OrderSubmissionScreen from "../screens/OrderSubmissionScreen";
import ProfileScreen from "../screens/ProfileScreen";
import SearchScreen from "../screens/SearchScreen";
import LoginRegisterScreen from "../screens/LoginRegisterScreen";
import CodeEntryScreen from "../screens/CodeEntryScreen";
import Colors from "../constants/Colors";
import IconWithBadge from "../components/UI/IconWithBadge";
const HomeNavigator = createStackNavigator(
{
Home: HomeScreen,
ProductDetails: ProductDetailsScreen,
Categories: CategoriesListScreen,
Products: ProductsScreen,
Search: SearchScreen,
},
{
defaultNavigationOptions: {
headerShown: false,
},
}
);
const CartNavigator = createStackNavigator(
{
Cart: CartScreen,
OrderSubmission: OrderSubmissionScreen,
ProductDetails: ProductDetailsScreen,
OrdersList: OrdersListScreen,
},
{
defaultNavigationOptions: {
headerShown: false,
},
}
);
const LoginRegisterNavigator = createStackNavigator(
{
LoginRegister: LoginRegisterScreen,
CodeEntry: CodeEntryScreen,
},
{
defaultNavigationOptions: {
headerShown: false,
},
}
);
const OrdersNavigator = createStackNavigator(
{
OrdersList: OrdersListScreen,
OrderDetails: OrderDetailsScreen,
},
{
defaultNavigationOptions: {
headerShown: false,
},
}
);
const ProfileNavigator = createStackNavigator({
Profile: ProfileScreen,
});
const tabScreenConfig = {
Profile: {
screen: ProfileNavigator,
navigationOptions: {
tabBarLabel: "حسابي",
tabBarIcon: (tabInfo) => {
return (
<Ionicons name="ios-person" size={25} color={tabInfo.tintColor} />
);
},
},
},
Orders: {
screen: OrdersNavigator,
navigationOptions: {
tabBarLabel: "طلباتي",
tabBarOptions: {
style: {
// borderWidth: 0,
// borderTopColor: "transparent"
},
labelStyle: {
fontFamily: "cairo-bold",
},
tabStyle: {
height: 60,
paddingVertical: 5,
},
activeTintColor: Colors.primary,
},
tabBarIcon: (tabInfo) => {
return (
<Ionicons name="ios-paper" size={25} color={tabInfo.tintColor} />
);
},
},
},
Cart: {
screen: CartNavigator,
navigationOptions: {
tabBarVisible: false,
tabBarLabel: "سلة التسوق",
tabBarIcon: (tabInfo) => {
return (
<IconWithBadge name="ios-cart" size={25} color={tabInfo.tintColor} />
);
},
},
},
Home: {
screen: HomeNavigator,
navigationOptions: {
tabBarLabel: "تسوق",
tabBarIcon: (tabInfo) => {
return <Ionicons name="ios-home" size={25} color={tabInfo.tintColor} />;
},
},
},
};
const MainAppTabsNavigator =
Platform.OS === "android"
? createMaterialBottomTabNavigator(tabScreenConfig, {
initialRouteName: "Home",
tabBarOptions: {
labelStyle: {
fontFamily: "cairo-bold",
},
activeColor: Colors.primary,
shifting: true,
},
})
: createBottomTabNavigator(tabScreenConfig, {
initialRouteName: "Home",
tabBarOptions: {
labelStyle: {
fontFamily: "cairo-bold",
},
tabStyle: {
height: 60,
paddingVertical: 5,
},
activeTintColor: Colors.primary,
},
});
// handleTabPress = ({ navigation, defaultHandler }) => {
// navigation.popToTop();
// defaultHandler();
// };
const test = createStackNavigator(
{
tabs: MainAppTabsNavigator,
LoginRegister: LoginRegisterNavigator,
},
{
defaultNavigationOptions: {
headerShown: false,
},
}
);
export default createAppContainer(test);
Here is my code for App.js:
import React, { useState, useEffect } from "react";
import { View, Text, StyleSheet } from "react-native";
import { AppLoading } from "expo";
import * as Font from "expo-font";
import { createStore, combineReducers, applyMiddleware } from "redux";
import { Provider, useDispatch } from "react-redux";
import { composeWithDevTools } from "redux-devtools-extension";
import ReduxThunk from "redux-thunk";
import * as SplashScreen from "expo-splash-screen";
import categoriesReducer from "./store/reducers/categories";
import productsReducer from "./store/reducers/products";
import cartReducer from "./store/reducers/cart";
import ordersReducer from "./store/reducers/orders";
import authReducer from "./store/reducers/auth";
import addressReduceer from "./store/reducers/address";
import AppNavigator from "./navigation/AppNavigator";
import { NavigationContainer } from '@react-navigation/native';
import * as productsActions from "./store/actions/products";
import * as categoriesActions from "./store/actions/categories";
import * as addressActions from "./store/actions/address";
import * as authActions from "./store/actions/auth";
const rootReducer = combineReducers({
categories: categoriesReducer,
products: productsReducer,
cart: cartReducer,
orders: ordersReducer,
auth: authReducer,
address: addressReduceer,
});
const store = createStore(
rootReducer,
composeWithDevTools(),
applyMiddleware(ReduxThunk)
);
const fetchFonts = () => {
return Font.loadAsync({
"cairo-regular": require("./assets/fonts/Cairo-Regular.ttf"),
"cairo-bold": require("./assets/fonts/Cairo-Bold.ttf"),
"cairo-light": require("./assets/fonts/Cairo-Light.ttf"),
"cairo-semiBold": require("./assets/fonts/Cairo-SemiBold.ttf"),
lateef: require("./assets/fonts/LateefRegOT.ttf"),
"mada-regular": require("./assets/fonts/Mada-Regular.ttf"),
"mada-bold": require("./assets/fonts/Mada-Bold.ttf"),
"openSans-regular": require("./assets/fonts/OpenSans-Regular.ttf"),
});
};
const AppWrapper = () => {
return (
<Provider store={store}>
<App />
</Provider>
);
};
const App = () => {
const dispatch = useDispatch();
const [fontLoaded, setFontLoaded] = useState(false);
const [appIsReady, setAppIsReady] = useState(false);
const preventAutoHide = async () => {
try {
await SplashScreen.preventAutoHideAsync();
} catch (e) {
console.warn(e);
}
prepareResources();
};
useEffect(() => {
preventAutoHide();
}, []);
const prepareResources = async () => {
try {
await Promise.all([
dispatch(productsActions.fetchProducts()),
dispatch(categoriesActions.fetchCategories()),
dispatch(productsActions.fetchPromotionProducts()),
// eslint-disable-next-line prettier/prettier
dispatch(addressActions.fetchAddress()),
dispatch(authActions.fetchUserDetails()),
]);
setAppIsReady(true);
await SplashScreen.hideAsync();
} catch (err) {
console.log(err.message);
}
};
if (!appIsReady) {
return (
<View style={styles.container}>
<Text style={styles.text}>SplashScreen Demo! 👋</Text>
</View>
);
}
if (!fontLoaded) {
return (
<AppLoading
startAsync={fetchFonts}
onFinish={() => setFontLoaded(true)}
/>
);
}
return (
<Provider store={store}>
<AppNavigator />
</Provider>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
backgroundColor: "#aabbcc",
},
text: {
color: "white",
fontWeight: "bold",
},
});
export default AppWrapper;
Here is my code for the store reducer which I want to access the addresses state. If there is an address or not, I want to change the label and the icon based on that.
import { FETCH_ADDRESS, INTIALIZE_ADDRESS } from "../actions/address";
import Address from "../../models/address";
const initialState = {
addresses: [],
};
export default (state = initialState, action) => {
switch (action.type) {
case INTIALIZE_ADDRESS:
return {
...state,
addresses: initialState.addresses,
};
case FETCH_ADDRESS:
const newAddress = new Address(
action.addressData.id,
action.addressData.addressName,
action.addressData.sector,
action.addressData.streetNo,
action.addressData.houseNo,
action.addressData.region,
action.addressData.city,
action.addressData.landmark
);
return {
...state,
addresses: state.addresses.concat(newAddress),
};
}
return state;
};