Passing parameter to custom hook

Viewed 560

There is lot of documentation about the hooks, but I don't seem to understand them well enough.

Code

const App = () => {
const [markers, setMarkers] = useState(null);

const fetchMarkers = async () => {
const res = await axios.get(`${process.env.REACT_APP_BASE_URL}/markers`);
setMarkers(res.data);
};

useEffect(() => {
fetchMarkers();
}, []);

useInterval(() => {
fetchMarkers();
}, 10000);
}

I've made a custom hook which returns an object, I can call it like this:

const location = useGeoLocation(); 

I would like to add markers as parameter to useGeoLocation hook. This can be achieved easily just by calling the function on code and adding markers.

Objective

My goal is to make sure that markers contains some value before calling useGeoLocation. Right now, geoLocation hooks parameter returns value of null, because application didn't have time to fetchMarkers and update the state.

I've tried

My first thought was to do something like this:

  if (markers) {
  const location = useGeoLocation(markers);
  }

But of course, like stated in rules of hooks, hooks can't be used conditionally.

UPDATED 10.1.2022 - useGeoLocation hook

Here I'm fetching users location. On success, I will compare users location to an array of markers & find the closest one to user. On error, I will return only a predefined location.

This doesn't work because onSuccess is executed before there is any data in markers(null). I'm not sure how to use if - else statement here, because I'm also using useEffect & useState.

Can someone help?

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 (!("geolocation" in navigator)) {
  onError();
}

navigator.geolocation.getCurrentPosition(onSuccess, onError);
}, []);

return location;
};
1 Answers

Add markers in the dependency array of useEffect hook of useGeoLocation and call navigator.geolocation.getCurrentPosition(onSuccess, onError) if the markers are available and in the else part you can call setLocation().

const useGeoLocation = (markers) => {
  const [location, setLocation] = useState({
    loaded: false,
    coordinates: { lat: "", lng: "" },
  });

  
  useEffect(() => {
      if (markers) {
          if (!("geolocation" in navigator)) {
            onError();
          }
      
          navigator.geolocation.getCurrentPosition(onSuccess, onError);
      } else {
        setLocation();
      }
  }, [markers]);

  return location;
};
Related