kalculated
kalculated

Reputation: 319

React Native Navigation: Conditionally render tab bar badge not working?

I am trying to show a tab bar badge for my notifications tab. If a user has a notification, after writing the notification in the backend, I set a field for the user "hasNotifications" as true. Once I click on the notifications tab, I set "hasNotifications" to false.

Here is my implementation:

function renderBadge() {

  Firebase.firestore()
  .collection('users')
  .doc(Firebase.auth().currentUser.uid)
  .onSnapshot(function(doc) { 

      if (doc.data().hasNotifications) {
          console.log("true")
          return true
      }
      else {
          console.log("null")
          return null
      }
      
  })
}

 
//Bottom Tabs
function Tabs() {
  
  return (

    <Tab.Navigator
    initialRouteName="Home"
    tabBarOptions={{
      activeTintColor:"#FFFFFF",
      inactiveTintColor:"#696969",
      style: {
        backgroundColor: '#000000',
        borderTopColor: "transparent"
      },
    }}>

      <Tab.Screen 
        name="Notificaton" 
        component={Notification}
        options={{
          tabBarLabel: ' ',
          tabBarIcon: ({ color, size }) => (
            <Ionicons name="md-notifications" size={size} color={color} />
          ),
          tabBarBadge: renderBadge() <----- Render red dot if true, no red dot if null

        }}
      />  

    </Tab.Navigator>
  );
}

The console logging shows me the listener is working, and returns true/null based on whether the user has notifications. But the tab bar badge does NOT show up. How can I fix this?

EDIT: Looks like when I set tabBarBadge: renderBadge(), the badge never shows up. When I set tabBarBadge: renderBadge, the badge always shows up. The listener is working fine, but this is not.

EDIT 2: I changed the function to const renderBadge = () => {, and it still doesn't work.

Upvotes: 2

Views: 2634

Answers (1)

Hero Wanders
Hero Wanders

Reputation: 3292

I know react (for browsers) better than react-native, but if the paradigm is the same, you should change the following aspects:

  • Instead of directly changing a variable in the function scope, make use of useState to hold the boolean value; change the value provided by its setter function
    • This will react allow to notice the change when it happens and make it -- react.
  • Your Firebase access is probably some kind of side-effect, so you should use useEffect, perhaps with Firebase.auth().currentUser.uid as a dependency.

The result could be similar to this:

function useNotificationsBadge() {
    const [hasNotifications, setHasNotifications] = useState(null);
    const userId = Firebase.auth().currentUser.uid;

    useEffect(
        () => Firebase.firestore()
            .collection('users')
            .doc(userId)
            .onSnapshot(function(doc) {
                const newHasNotifications = doc.data().hasNotifications ? true : null;
                setHasNotifications(newHasNotifications);
            }),
        [userId]
    );

    return hasNotifications;
}

In your component you can then write;

    ...
    const hasNotifications = useNotificationsBadge();
    ...

        tabBarBadge: hasNotifications

My personal recommendation would be to replace null by false in this snippet to make the API more clear.

Upvotes: 2

Related Questions