Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add badge to tab-bar in react-native?

I am using the tabnavigator (createbottomBottomTabNavigator) and need help with the bage count using redux.

like image 407
user11426267 Avatar asked Mar 04 '23 02:03

user11426267


2 Answers

You can always create your custom component, in this case, the tab item (<TabBarItem />).

I have created a simple demo, here is the snack link: https://snack.expo.io/@abranhe/tab-badge-count-redux

In this example, you have 3 pages/tabs (apps, navigation, and profile) so you need to manage the notification counter of every one of them. So we start by creating the component, I am using Native Base to have pre-built components. Also, we have the following initial state.

export default {
  apps: {
    notificationCount: 7,
  },
  navigation: {
    notificationCount: 0,
  },
  profile: {
    notificationCount: 3,
  },
};

TabBarItem.js

import React from 'react';
import { connect } from 'react-redux';
import { View, StyleSheet } from 'react-native';
import { Badge, Button, Icon, Text } from 'native-base';

const renderBadge = ({ badgeProps, counter }) => (
  <Badge {...badgeProps} style={styles.badge}>
    <Text style={styles.notificationText}>{counter}</Text>
  </Badge>
);

function TabBarItem({ notificationCount, badgeProps, icon, label, color }) {
  let counter = 0;

  switch (icon) {
    case 'apps':
      counter = notificationCount.apps;
      break;
    case 'navigate':
      counter = notificationCount.navigation;
      break;
    case 'person':
      counter = notificationCount.profile;
      break;
    default:
      counter = 0;
  }

  return (
    <View style={styles.container}>
      {counter > 0 && renderBadge({ counter, badgeProps })}
      <View style={styles.iconContainer}>
        <Icon name={icon} style={{ color }} />
        <Text style={{ color, ...styles.label }}>{label}</Text>
      </View>
    </View>
  );
}

const styles = ....;

const mapStateToProps = state => ({
  notificationCount: {
    apps: state.apps.notificationCount,
    navigation: state.navigation.notificationCount,
    profile: state.profile.notificationCount,
  },
});

export default connect(mapStateToProps)(TabBarItem);

This is just a work-around, and as you see I am creating a component connected to Redux and checking which tab should render depending on the icon name prop. If we have only one tab with notifications, only we needed to access the data on Redux, and automatically render.

We need to create a reducer to handle Increment and Decrement actions

export default function reducer(state = initialState, action = {}) {
  switch (action.type) {
    case 'APPS.INCREMENT':
      return {
        ...state,
        apps: {
          ...state.apps,
          notificationCount: state.apps.notificationCount + 1,
        },
      };

    case 'APPS.DECREMENT':
      return {
        ...state,
        apps: {
          ...state.apps,
          notificationCount: state.apps.notificationCount - 1,
        },
      };
  ...
}

Well also we need to add the created component:

import React from 'react';
import { connect } from 'react-redux';
import { StyleSheet } from 'react-native';
import { Container, Content, H1, H3 } from 'native-base';
import NotificationCounter from '../components/NotificationCounter';

const Apps = ({ notificationCount, dispatch }) => (
  <Container>
    <Content contentContainerStyle={styles.container}>
      <H1>Apps Page</H1>
      <NotificationCounter
        handleIncrement={() => dispatch({ type: 'APPS.INCREMENT' })}
        handleDecrement={() => dispatch({ type: 'APPS.DECREMENT' })}
      />
      <H3>Notification Count: {notificationCount}</H3>
    </Content>
  </Container>
);

const styles = ...

const mapStateToProps = state => ({
  notificationCount: state.apps.notificationCount,
});

export default connect(mapStateToProps)(Apps);

We are using dispatch({ type: 'APPS.INCREMENT' }) to trigger the action that increments the notifcations for the apps tab.

The <NotificationCounter /> component code:

import React from 'react';
import { View, StyleSheet } from 'react-native';
import { Button, Text } from 'native-base';

export default ({ handleDecrement, handleIncrement }) => (
  <View style={styles.container}>
    <Button onPress={handleDecrement}>
      <Text>Decrement</Text>
    </Button>
    <Button onPress={handleIncrement}>
      <Text>Increment</Text>
    </Button>
  </View>
);

const styles = ...
like image 121
abranhe Avatar answered Mar 13 '23 04:03

abranhe


There is custom way to do this using redux, you can make your custom component using the same :-

screen: NotificationScreen,
    navigationOptions: {
      tabBar: (state, acc) => ({
        icon: ({ tintColor, focused }) => (
          <BadgeTabIcon
            iconName="notification"
            size={26}
            selected={focused}
          />
        ),
        visible: (acc && acc.visible !== 'undefined') ? acc.visible : true,
      }),
    },
  },

where,

export default connect(state => ({
  notificationCount: state.notifications.count,
}))(({ dispatch, nav }) => (
  <View>
    <TabIcon {...props} />
    {
      props.notificationCount > 0 ?
        <View style={{ position: 'absolute', right: 10, top: 5, backgroundColor: 'red', borderRadius: 9, width: 18, height: 18, justifyContent: 'center', alignItems: 'center' }}>
          <Text style={{ color: 'white' }}>{props.notificationCount}</Text>
        </View> : null
    }
  </View>
));

Read here more

Also, official tabnavigation in react native have the support for the same, you can read here more

I hope this helps...Thanks :)

like image 34
abhikumar22 Avatar answered Mar 13 '23 05:03

abhikumar22