Search code examples
reactjsreact-nativereact-functional-component

How do I unMount a running function?


I created a stack structure here. As you can see, I made a timer with a Setinterval function in Home.js. The Setinterval function works in Home.js, but it continues to work when I go to the Details page. How can I make it stop when I switch to the Details page?

Router.js

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import Home from "./components/Home"
import Details from "./components/Details"
import Other from "./components/Other"
    
const Stack = createStackNavigator();

const Router= ()=> {
  return (
    <NavigationContainer>
      <Stack.Navigator screenOptions={{gestureEnabled:true}} >
        <Stack.Screen name="Home" component={Home} />
        <Stack.Screen name="Details" component={Details} />
        <Stack.Screen name="Other" component={Other} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default Router

Home.js

import React, {useState, useEffect} from 'react';
import {Text, View, Button,StatusBar} from 'react-native';

const Home = ({navigation}) => {
  const [timer, setTimer] = useState(1);


  useEffect(()=>{
    const myTimer=setInterval(()=>{
      setTimer(timer=>timer+1)
    },2000)

    return ()=>clearInterval(myTimer)
  })

  console.log("timer   :",timer)

  return (
    <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
      <StatusBar hidden/>
      <Text>Home</Text>
      <Button
        title="Go to Details"
        onPress={() => navigation.navigate('Details')}
      />
    </View>
  );
};

export default Home;

Details.js

import React,{useState,useEffect} from 'react';
import {Text,View,Button} from "react-native"

const Details = ({ navigation }) => {
    return (
        <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Details Screen</Text>
        <Button
          title="Go to Other..."
          onPress={() => navigation.navigate('Other')}
        />
      </View>
    );
}

export default Details;

any help is appreciated


Solution

  • An example of using a React ref to hold the timer ref. It can be cleared in the button's onPress callback handler. I think a related issue is that the useEffect hook hasn't any dependencies and the callback updates state, so it triggers rerenders (though the cleanup function should handle this case). Either way, typically when setting up interval timers you only set them up once when the component mounts, clearing the timer when it unmounts.

    import React, { useState, useEffect, useRef } from 'react';
    import {Text, View, Button,StatusBar} from 'react-native';
    
    const Home = ({ navigation }) => {
      const [timer, setTimer] = useState(1);
      const timerRef = useRef(null);
    
      useEffect(()=>{
        timerRef.current = setInterval(() => setTimer(timer => timer + 1), 2000)
    
        return () => clearInterval(timerRef.current)
      }, []); // <-- setup interval only once when component mounts
    
      return (
        <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
          <StatusBar hidden/>
          <Text>Home</Text>
          <Button
            title="Go to Details"
            onPress={() => {
              navigation.navigate('Details');
              clearInterval(timerRef.current); // <-- clear interval on navigation
            }}
          />
        </View>
      );
    };