Raj Shah
Raj Shah

Reputation: 738

How to useEffect cleanup function in react native?

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in %s.%s, a useEffect cleanup function,

const Drawer = createDrawerNavigator();

const App = () => {
  const [isLoading, setIsLoading] = React.useState(true);
  const [userToken, setUserToken] = React.useState(null);

  const authContext = React.useMemo(() => ({
    SignIn: () => {
      setUserToken('qwertyuiop');
      setIsLoading(false);
    },
    SignOut: () => {
      setUserToken(null);
      setIsLoading(false);
    },
    SignUp: () => {
      setUserToken('qwe');
      setIsLoading(false);
    },
  }));

  useEffect(() => {
    setTimeout(() => {
      setIsLoading(false);
    }, 1000);
  }, []);

  if (isLoading) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <ActivityIndicator size="large" />
      </View>
    );
  }

  console.log("userToken", userToken)
  console.log("authContext", authContext)
  return (
    <AuthContext.Provider value={authContext}>
      <NavigationContainer>
        {userToken !== null ? (
          <Drawer.Navigator drawerContent={props => <DrawerContent {...props} />}>
            <Drawer.Screen name="HomeDrawer" component={MainTabScreen} />
            <Drawer.Screen name="Support" component={SupportScreen} />
            <Drawer.Screen name="Setting" component={SettingScreen} />
            <Drawer.Screen name="Bookmark" component={BookmarkScreen} />
          </Drawer.Navigator>
        )
          :
          <RootStackScreen />
        }
      </NavigationContainer>
    </AuthContext.Provider>
  );
}

Upvotes: 0

Views: 3477

Answers (4)

Sunil Kumar
Sunil Kumar

Reputation: 1796

Solution

Using Axios:

import axios from 'axios';

Component:

const Home: React.FC = () => {

let cancelToken: any = axios.CancelToken;
let source = cancelToken.source();

useEffect(() => {
    (async () => {

      try {
        const data = await axios.get("https://<you-api-url>", {
            cancelToken: source.token
        });
        
      }catch (error) {
        if (axios.isCancel(error)) {
          console.log('Request canceled', error.message);
        } else {
          // handle error
          console.log(error);
        }
      }

    })();

    return () => {
      //when the component unmounts
      console.log("component unmounted");

      // cancel the request (the message parameter is optional)
      source.cancel('Operation canceled by the user.');
    }
}, []); //End UseEffect

return ();

};

export default Home;

Above implementation is per the original Axios docs, read here to understand in detail.

Upvotes: 0

Ardy Febriansyah
Ardy Febriansyah

Reputation: 768

To prevent component not updating state when un-mounted you can use useRef and cleanup function

const mounted = useRef(false);

useEffect(() => {
    mounted.current = true;

    setTimeout(() => {
      if (mounted.current) {
        setIsLoading(false);
      }
    }, 1000);

    return function cleanup() {
      mounted.current = false;
    }
}, []);

Upvotes: 0

Diyorbek Sadullaev
Diyorbek Sadullaev

Reputation: 477

You should always clear setTimeouts setIntervals on unmount.

useEffect(() => {
  const timeout = setTimeout(() => {
    setIsLoading(false);
  }, 1000);

  return () => clearTimeout(timeout);
}, []);

You received this warning because setTimeout was still on process even of the component was unmounted.

Upvotes: 1

CevaComic
CevaComic

Reputation: 2104

The syntax is very easy:

useEffect(() => {
    setTimeout(() => {
      setIsLoading(false);
    }, 1000);
    return () => someCleanUp() // your cleanup function
}, []);

Upvotes: 0

Related Questions