Home > other >  Unsubscribe from watchPositionAsync with useEffect return function
Unsubscribe from watchPositionAsync with useEffect return function

Time:04-05

Using react native with expo-location for a mobile app, I would like to unsubscribe from Location.watchPositionAsync which returns a promise with a remove() method to unsubscribe. I call the function within a useEffect hooks, but i don't know how to correctly return a cleanup function with the watchPositionAsync promise resolved.

Any suggestions?

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

import * as Location from "expo-location";

export const GpsComponent = function () {
    const [location, setLocation] = useState(null);

    useEffect(() => {
        const positionSubscription = async () => {
            const positionSubscribe = await Location.watchPositionAsync(
                { accuracy: Location.LocationAccuracy.BestForNavigation },
                (newLocation) => {
                    setLocation(newLocation);
                }
            );

            return positionSubscribe;
        };

        /*return () => {
            positionSubscription.remove();
            console.log("Unsubscribed from WatchPositionAsync");
        };*/

    }, [setLocation]);

    return (
        <View>
            <Text>{JSON.stringify(location)}</Text>
        </View>
    );
};

CodePudding user response:

I'm not familiar with react-native but to my understanding Location.watchPositionAsync may return subscription object with some delay and potentially component may be unmounted before that Location.watchPositionAsync resolves.

So I'd use let and null-check:

useEffect(() => {
    let subscription ;
    const subscribe = async () => {
        subscription = await Location.watchPositionAsync(
            { accuracy: Location.LocationAccuracy.BestForNavigation },
            (newLocation) => {
                setLocation(newLocation);
            }
        );

    };
    subscribe ();
    
    return () => {
      subscription && subscription.remove();
      // or `subscription?.remove();`
    }
}, []);

Also setLocation is referentially stable so legitimately can be excluded from dependencies list(see "Notes" section at https://reactjs.org/docs/hooks-reference.html#usestate)

CodePudding user response:

I finally found a way to unsubscribe to watchPositionAsync using useRef

import { useState, useEffect, useRef } from "react";
import { Text, View } from "react-native";

import * as Location from "expo-location";

export const GpsComponent = function () {
    const [location, setLocation] = useState(null);
    const unsubscribe = useRef(() => undefined);

    useEffect(() => {
        const subscribe= async () => {
            
            const positionSubscription = await Location.watchPositionAsync(
                { accuracy: Location.LocationAccuracy.BestForNavigation },
                (newLocation) => {
                    setLocation(newLocation);
                }
            );

           unsubscribe.current=()=>{positionSubscription?.remove()}
        };

     return ()=>{unsubscribe.current()}
    }, []);

    return (
        <View>
            <Text>{JSON.stringify(location)}</Text>
        </View>
    );
};

It 's also possible to use an object and modify a property after the async function's promise is resolved.

  • Related