简体   繁体   中英

React native disable timer in bottom navigation not working

I have 4 screens in bottom navigation. The first screen consists of a map with the timer of 10s. As soon as the timer get executed the api is hit.

But when a user switch the screen with bottom navigation tab item. The timer still works in background and due to which the other api start having lag.

How to make sure the timer only works when that screen is focused?

I tried updating the name of screen user is navigating using useContext however when the timer execute it do not return the update name of the screen. every time it returns the older screen name.

This code is in all the 4 bottom navigation screens. As I have observed useEffect only works once. and whenever user clicks it second time this hook do not get trigger.

HOME SCREEN

  const {activeScreenFun, activeScreen, previousScreen} = useNavigationCustom();
    
      React.useEffect(() => {
        const unsubscribe = navigation.addListener('tabPress', e => {
          activeScreenFun('Home');
        });
    
        return unsubscribe;
      }, [navigation]);
    
      useEffect(() => {
        activeScreenFun('Home');
      }, []);

Timer

  useEffect(() => {
        if (timer) {
          let interval = setInterval(() => {
            getAPiData();
          }, 10000);
    
          return () => {
            clearInterval(interval);
          };
        } 
      }, [timer]);

NavigationCustomProvider Context

export function NavigationCustomProvider({children}) {
  const [activeScreen, setActiveScreen] = useState('');
  const [previousScreen, setPreviousScreen] = useState('');

  const activeScreenFun = useCallback(async function (activeScreenSelected) {   
    setPreviousScreen(activeScreen);
    setActiveScreen(activeScreenSelected);
  });

  const getActiveScreenFun = useCallback(() => {
    return activeScreen;
  });

Bottom Navigation Code

export default function MainScreen() {
  return (
    <NavigationCustomProvider>
      <MainLayout>
        <MainLayoutScreen
          name={HOME_ROUTE}
          icon={TrackItIcon}
          activeIcon={TrackItActiveIcon}
          component={HomeScreen}
        />
        <MainLayoutScreen
          name={ATTENDACE_ROUTE}
          icon={AttendanceIcon}
          activeIcon={AttendanceActiveIcon}
          component={AttendanceScreen}
        />
        <MainLayoutScreen
          name={NOTIFICATION_ROUTE}
          icon={NotificationIcon}
          activeIcon={NotificationActiveIcon}
          component={NotificationScreen}
        />
        <MainLayoutScreen
          name={MY_ACCOUNT_ROUTE}
          icon={AccountIcon}
          activeIcon={AccountActiveIcon}
          component={ProfileScreen}
        />
      </MainLayout>
    </NavigationCustomProvider>
  );
}

TAB BAR CODE

routes = children.map(x => ({
    name: x.props.name,
    icon: x.props.icon,
    activeIcon: x.props.activeIcon,
    component: x.props.component,
  }));
 <Tab.Navigator
        barStyle={{backgroundColor: theme.colors.white}}
        activeColor={theme.colors.primary}
        shifting={true}
        labeled={true}>
        {routes.map(x => {
          let Icon = x.icon;
          let ActiveIcon = x.activeIcon;
          return (
            <Tab.Screen
              key={x.name}
              name={x.name}
              component={x.component}
              options={{
                tabBrColor: theme.colors.white,
                tabBarIcon: ({focused}) =>
                  focused ? <ActiveIcon /> : <Icon />,
              }}
            />
          );
        })}
      </Tab.Navigator>

A new timer instance is created for each new component rerender.

Even if you clear an instance of the timer when the component unmounts, previously created instances are still running in the background.

you need to persist a single instance of timer across all component rerender cycles.

React provide hook useRef to persist value for all component render cycle.

 let interval = React.useRef(null);

useEffect(() => {
  if (timer) {
    // Assign and persist Timer value with ref
    interval.current = setInterval(() => {
      getAPiData();
    }, 10000);

    return () => {
      if (interval.current) {
        clearInterval(interval);
      }
    };
  }
}, [timer]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM