Developer Relations Engineer
IN THIS ARTICLE
    GitHubGitHub

    GitHub Repo

    GitHub Repo

    Icon badges, or notification badges, are useful UI elements in any Android or iOS app. They allow icons to become alive and display important data to the user in realtime. They might show how many users are online, a notification count, or the number of unread messages. You can see them being used by app icons on Android and iOS, as well as in apps like Facebook, Snapchat, Instagram, and YouTube.

    Luckily, with PubNub, building realtime notification badges is simple. We’ll be using some useful React Native libraries to clone Facebook Messenger and add badges to the icons.

    The final result will be a skeleton app that looks like:

    facebook clone active users realtime badge

     

    We will also be using PubNub for realtime updates to the badge. Get your free PubNub API keys here to enable Pub/Sub Messaging and Presence. Important: You must enable Presence in the PubNub Admin Dashboard for this app to work.

    Creating a Facebook Messenger Clone in React Native

    Before diving into the code, you will need to install Node.js, if you haven’t already. Next, to use React Native, you will also need to install the React Native CLI, through which we can initialize and run our project.

    sudo npm install -g react-native-cli
    sudo npm install -g react-native

    Now, let’s build a blank react-native app.

    react-native init realtimebadge && cd realtimebadge

    Add React Native Elements, React Native Vector Icons, React Navigation, React Native Gesture Handler, and React PubNub to your project.

    npm install --save react-native-elements react-native-vector-icons react-pubnub react-native-gesture-handler react-navigation && react-native link

    Note
    : you may need to manually link react-native-gesture-handler if automatically linking does not work. Follow the steps here to manually link react-native-gesture-handler.

    In App.js, include PubNub into your app and initialize a PubNub instance with the free API keys you received above. Under componentDidMount(), subscribe to an arbitrary channel, with the boolean flag withPresence set to true.

    import React, { Component } from "react";
    import { Text } from "react-native";
    import PubNubReact from 'pubnub-react';
    
    export default class App extends Component {
      constructor(props) {
        super(props);
        this.pubnub = new PubNubReact({
        publishKey: "INSERT-PUB-KEY-HERE",
        subscribeKey: "INSERT-SUB-KEY-HERE"
        });
        this.state = {
        };
    
        this.pubnub.init(this);
      }
    
      componentDidMount() {
        this.pubnub.subscribe({
          channels: ['channel1'],
          withPresence: true
        });
      }
    
      render() {
        return <Text>Hello world.</Text>;
      }
    }

    Create a new folder in the root directory called src. Within src, create three more folders called navigation, styles, and screens.

    We’ll need to create a blank screen as a default screen for each navigation view. You may modify this screen for your use cases. For our demo purposes, it will simply display “Empty screen.” as text. Create a file called Empty.js and place it inside src/screens.

    import React from "react";
    import { StatusBar, StyleSheet, Text } from "react-native";
    import { SafeAreaView } from "react-navigation";
    import AppStyles from '../styles/Styles';
    
    export class Empty extends React.Component {
      static navigationOptions = {
        headerTitle: "Empty"
      };
      render() {
        return (
          <SafeAreaView>
            <StatusBar
            backgroundColor={AppStyles.colors.accentColor}
            barStyle={AppStyles.barStyle}
            />
            <Text>Empty screen.</Text>
          </SafeAreaView>
        );
      }
    }

    The styling for the UI can be found in styles/Styles.js. Customize it at your will.

    const AppStyles = {
        colors: {
            accentColor: '#0084ff',
            inactiveGreyColor: '#626262',
            lightGreyColor: '#7f8c8d',
            separator: '#bdc3c7',
            white: 'white',
            black: 'black',
            grey: 'grey',
            green: 'green',
            onlineGreen: '#2ecc71',
            lightWhite: '#f9f9f9'
        },
        fonts: {
            FONT_REGULAR: 'Roboto-Regular',
            FONT_MEDIUM: 'Roboto-Medium',
            FONT_LIGHT: 'Roboto-Light',
            FONT_THIN: 'Roboto-Thin'
        },
        barStyle: "light-content"
    };
    
    export default AppStyles;

    To create Facebook Messenger styled navigation bars, we’ll be using react-navigation.

    The top navigation bar will include “Messages,” “Active,” “Groups,” and “Calls” as a material-design themed tab bar from react-navigation’s createMaterialTopTabNavigator. Create a file called Messages.js and include the following code below.

    import { Platform } from 'react-native';
    import { createMaterialTopTabNavigator, createAppContainer } from 'react-navigation';
    
    import Empty from "../screens/Empty";
    
    import AppStyles from '../styles/Styles';
    
    export const Messages = createMaterialTopTabNavigator({
      MessagesScreen: {
        screen: Empty,
        navigationOptions: { header: null, title: 'Messages' }
      },
      ActiveScreen: {
        screen: Empty,
        navigationOptions: { header: null, title: 'Active' }
      },
      GroupsScreen: {
        screen: Empty,
        navigationOptions: { header: null, title: 'Groups' }
      },
      CallsScreen: {
        screen: Empty,
        navigationOptions: { header: null, title: 'Calls' }
      }
    },
    {
      tabBarPosition: 'top',
      tabBarOptions: {
        activeTintColor: AppStyles.colors.accentColor,
        inactiveTintColor: AppStyles.colors.inactiveGreyColor,
        pressColor: AppStyles.colors.lightGreyColor,
        labelStyle: {
          fontWeight: 'bold',
          fontSize: Platform.OS === 'ios' ? 11 : 12,
          fontFamily: AppStyles.fonts.FONT_MEDIUM
        },
        indicatorStyle: {
          backgroundColor: AppStyles.colors.accentColor
        },
        style: {
          backgroundColor: 'white'
        }
      }
    });

    If you export this component into your App.js render, you will see something like this:

    facebook navigation bar

    Now, let’s build the base navigator of the app which includes a bottom tab navigation bar as well as the top bar that we just made.

    Conveniently, we can use Icon from react-native-elements as the tabBarIcon. We’ll be later changing these icons into BadgedIcons. Create a file named Navigation.js inside src/Navigation and begin by adding the bottom icons.

    import React from 'react';
    import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
    import { Badge, Icon, withBadge } from 'react-native-elements'
    
    import { Messages } from './Messages';
    
    import AppStyles from '../styles/Styles';
    import Empty from "../screens/Empty";
    
    const MessagesIcon = ({ tintColor }) => (
      <Icon
        type="ionicon"
        name="ios-chatbubbles"
        size={24}
        color={tintColor}
      />
    );
    const UsersIcon = ({ tintColor }) => (
      <Icon
        type="material"
        name="supervisor-account"
        size={24}
        color={tintColor}
      />
    );
    
    const DiscoverIcon = ({ tintColor }) => (
      <Icon
        type="ionicon"
        name="md-compass"
        size={24}
        color={tintColor}
      />
    );

    Just like we did for the top bar, we can easily build a bottom navigation bar with icons by using createBottomTabNavigator.

    const BottomTabNavigation = createBottomTabNavigator({
      MessagesScreen: {
        screen: Messages,
        navigationOptions: {
          header: null,
          tabBarIcon: MessagesIcon
        }
      },
      UsersScreen: {
        screen: Empty,
        navigationOptions: {
          header: null,
          tabBarIcon: UsersIcon
        }
      },
      DiscoverScreen: {
        screen: Empty,
        navigationOptions: {
          header: null,
          tabBarIcon: DiscoverIcon
        }
      }
    },
    {
      tabBarOptions: {
        showLabel: false,
        activeTintColor: '#0084ff',
        inactiveTintColor: AppStyles.colors.inactiveGreyColor,
        pressColor: '#7f8c8d'
      }
    });

    To include this navigation component to the App, first create a default export.

    const Navigation = createAppContainer(BottomTabNavigation);
    
    export default Navigation;

    And then add it to your App.js as follows.

    import React, { Component } from "react";
    import Navigation from "./src/navigation/Navigation";
    import PubNubReact from 'pubnub-react';
    
    export default class App extends Component {
      constructor(props) {
        super(props);
        this.pubnub = new PubNubReact({
        publishKey: "INSERT-PUB-KEY-HERE",
        subscribeKey: "INSERT-SUB-KEY-HERE"
        });
        this.state = {
        };
    
        this.pubnub.init(this);
      }
    
      componentDidMount() {
        this.pubnub.subscribe({
          channels: ['channel1'],
          withPresence: true
        });
      }
    
      render() {
        return <Navigation />;
      }
    }

    At this point, we’ve finished up the UI and we are ready to include badges into our app.

    Adding Badges to Icons in React Native

    To use react-native-elements’ badge, let’s import it from `react-native-elements`.

    import { withBadge } from 'react-native-elements' 
    

    Now instead of the MessagesIcon we created, we can replace it with a BadgedIcon.

    const MessagesBadge = withBadge(5)(Icon)

    Note: we can pass in any count inside the first withBadge argument.

    And simply change the Icon render to MessagesBadge.

    const MessagesIcon = ({ tintColor }) => (
      <MessagesBadge
        type="ionicon"
        name="ios-chatbubbles"
        size={24}
        color={tintColor}
      />
    );
    

    You have now added a badge to the messages icon that looks like this:

    realtime badges in facebook app

    Active Users Badge

    As of now, we’ve hardcoded the badge count for the MessagesIcon. However, we can make our UsersIcon badge become alive by using PubNub Presence to find the number of users connected.

    In App.js, after connecting to PubNub, we can have each user subscribe to a global channel. Then, with a Presence hereNow() call, we will be able to retrieve the number of users connected. We will update this value usersCount in the state and pass it into our navigation props, allowing us to access this value for our badge, in realtime.

    Your App.js should now look like this:

    import React, { Component } from "react";
    import Navigation from "./src/navigation/Navigation";
    import PubNubReact from 'pubnub-react';
    
    export default class App extends Component {
      constructor(props) {
        super(props);
        this.pubnub = new PubNubReact({
          publishKey: "INSERT-PUB-KEY-HERE",
          subscribeKey: "INSERT-SUB-KEY-HERE"
        });
        this.state = {
          userCount: 0,
        };
    
        this.pubnub.init(this);
      }
    
      componentDidMount() {
        this.pubnub.subscribe({
          channels: ['channel1'],
          withPresence: true
        });
    
        let presenceUsers;
        setInterval(() => {
          this.pubnub.hereNow(
          {
            includeUUIDs: true,
            includeState: true
          },
          (status, response) => {
            // handle status, response
            console.log(status);
            console.log(response);
            if (response != undefined) presenceUsers = response.totalOccupancy;
          }
        );
          this.setState({userCount: presenceUsers})
        }, 10000);
      }
    
      render() {
        return <Navigation screenProps={{userCount: this.state.userCount}}/>;
      }
    }

    Here, we use setInterval() to continuously check the number of users joined every 10 seconds (you may change this for your needs). Then, we store the user count in the state and pass it through the Navigation component as a screenProp. When rendering our badged icon, we can access it from the screenProps as userCount.

    As such, we need to change our UsersScreen to include an icon as well as the badge. This is an alternative way to use the badge compared to how we previously used it for the messages badge.

    UsersScreen: {
      screen: Empty,
      navigationOptions: ({ screenProps, navigation }) => ({
        header: null,
        tabBarIcon: () => (
          <View>
            <Icon
              type="material"
              name="supervisor-account"
              size={24}
            />
    
            <Badge
              value={screenProps.userCount}
              containerStyle={{ position: 'absolute', top: -4, right: -4 }}
            />
        </View>
        )
      })
    },

    Congratulations! You have added a realtime badge feature into your app that displays the active users count on an icon using PubNub Presence. As more users open and join the app, the badge will update the user count accordingly. Here is the result:

    realtime badge facebook gif

    Conclusion

    In this tutorial, you learned how to build a basic messaging app. Then, you were able to add badges to icons in React Native. Finally, you used PubNub Presence to create an active users icon which displays the user count in its badge in realtime.

    Try PubNub today!

    Build realtime applications that perform reliably and securely, at global scale.
    Try Our APIs
    Try PubNub today!
    More From PubNub