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.