I've made a custom hook, which can be used to fetch users location and find nearest marker on map based on that information.
Right now it works, but first object it returns is useStates default value. Response looks like this:
{
coordinates: { lat: '', lng: '' },
loaded: false
}
After returning object first time, it starts to work like it should:
{
coordinates: { lat: 45.024335, lng: 19.277089 },
loaded: true
}
So basically I don't want that the hook sends empty objects, with no values. How can I fix this?
const useGeoLocation = (markers) => {
const [location, setLocation] = useState({
loaded: false,
coordinates: { lat: "", lng: "" },
});
const onSuccess = (location) => {
// User location succesfully fetched, converting data format.
const targetPoint = turf.point([
location.coords.latitude,
location.coords.longitude,
]);
// Fetching data from markers parameter and converting data format.
var arr = [];
markers.map((marker) => arr.push(turf.point(marker.location)));
var points2 = turf.featureCollection(arr);
// Calculating which marker is nearest to targetPoint.
var nearest = turf.nearestPoint(targetPoint, points2);
// Setting location of nearest marker to usestate.
setLocation({
loaded: true,
coordinates: {
lat: nearest.geometry.coordinates[0],
lng: nearest.geometry.coordinates[1],
},
});
};
const onError = () => {
setLocation({
loaded: true,
coordinates: {
lat: 65.024335,
lng: 27.277089,
},
});
};
useEffect(() => {
if (markers) {
if (!("geolocation" in navigator)) {
onError();
}
navigator.geolocation.getCurrentPosition(onSuccess, onError);
}
}, [markers]);
return location;
};
Instead of just returning the location object as a whole, you could split the return into an object with values for the data, a loading state, an error message if needs be. For example:
const useGeoLocation = (markers) => {
const [location, setLocation] = useState(undefined);
const [error, setError] = useState("");
const onSuccess = (location) => {
// Rest of the success handler...
setLocation({
coordinates: {
lat: nearest.geometry.coordinates[0],
lng: nearest.geometry.coordinates[1],
},
});
};
const onError = () => {
setLocation({
coordinates: {
lat: 65.024335,
lng: 27.277089,
},
});
setError("Some error message");
};
useEffect(() => {
if (markers) {
if (!("geolocation" in navigator)) {
onError();
}
navigator.geolocation.getCurrentPosition(onSuccess, onError);
}
}, [markers]);
return {
data: location,
isLoading: !location && !error,
error: error,
};
};
Then when calling the hook you can do:
const {data, isLoading, error} = useGeoLocation();
and check for the value of data, or that isLoading and error are false, before doing anything.