Andrew Einhorn
Andrew Einhorn

Reputation: 1163

Add an event listener to bottom tab with Expo router

I would like to add an event listener to one of my bottom tabs so I can trigger events when the user clicks on that tab. React navigation had a function navigator.addListener which allowed me to track this (see code below)

Does Expo router have some sort of equivalent?

import React, { useEffect } from 'react';
import { useNavigation } from '@react-navigation/native';

function MyTabScreen() {
  const navigation = useNavigation();

  useEffect(() => {
    const unsubscribe = navigation.addListener('tabPress', (e) => {
      console.log('Tab icon tapped');
      // Add your logic here
    });

    return unsubscribe;
  }, [navigation]);

  return (
    // Your tab screen content goes here
  );
}

export default MyTabScreen;

Upvotes: 2

Views: 3699

Answers (2)

Andrew Einhorn
Andrew Einhorn

Reputation: 1163

Ok, so I have found a solution to this.

The Tabs component from expo router has got a property called screenListeners, and you just need to implement the tabPress listener.

In my case, when the tabPress gets hit, I establish which tab was pressed, and if it is my tab of interest, I toggle a value in state. Then, in turn, I employ a useEffect in the tab's actual implementation to listen for that toggle, and execute the code I need to there.

Inside my Tabs _layout.tsx

import { Tabs } from 'expo-router/tabs'
import useStore from 'src/store'

export default function TabLayout() {
  const { stacksTabPress, toggleStacksTabPress } = useStore()

  return (
    <Tabs
      initialRouteName={'stacks'}
      screenOptions={}
      screenListeners={{
        // Monitor tab press and if 'test' tab is pressed, toggle value in zustand to trigger refetching of data from server
        tabPress: (e) => {
          const parts = e.target.split("-");
          const result = parts[0];
          if (result === 'test') {
            toggleStacksTabPress()
          }
        }
      }}
    >
      <Tabs.Screen
        name="test"
    />
)}

Inside my test index.tsx file

const test = () => {

  const { stacksTabPress } = useStore()

  useEffect(() => {
    console.log("#### Execute my code from the tab press here ... ")
  }, [stacksTabPress])
  
  ...

}

Upvotes: 6

Rafael Torres
Rafael Torres

Reputation: 11

This is what I did.

In my _layout.tsx Tabs tag

  screenListeners={{
    tabPress: (e) => {
      const target = e.target?.split("-")[0];
      if (target == "index") {
        EventRegister.emit(eventConfig.FEED_TAB_CLICKED);
      }
    },
  }}

Then, in your flatlist function:

const focused = useIsFocused();
const ref = useRef<FlatList | null>(null);

useFocusEffect(
  useCallback(() => {
    const feedListener = EventRegister.on(
      eventConfig.FEED_TAB_CLICKED,
      () => {
        if (focused) {
          ref.current?.scrollToOffset({ offset: 0, animated: true });
        }
      }
    );
    return () => EventRegister.removeEventListener(String(feedListener));
  }, [focused])
);
<FlatList
    ref={ref}...

Upvotes: 1

Related Questions