0

I am using the geolocation API inside my functional component, and my success and error callbacks for geolocation.watchPosition(success, error) have conditional code that is dependent on some state value that is going to change.

I do not want to initiate geolocation.watchPosition on mount inside useEffect.

I tried wrapping the callbacks with useCallback and passing the state value to the dependency array, but the callback still closes over the stale state value even though it is updated. Is there any workaround to this?

Simplified example:

 function Map() {
    const watchRef = useRef();
    const [isBool, setIsBool] = useState(false);
  
    function init() {
      watchRef.current = navigator.geolocation.watchPosition(success, error);
    }
  
    const success = useCallback((pos) => {
      if(isBool) {
        // do something...
        return;
      }
      // do something else...
    }, [isBool])
  
    function updateStateHandler() {
      setIsBool(true);
    }

    return // jsx...  
}
Sam
  • 375
  • 1
  • 5
  • 15
  • Why not set it on mount? What is the problem with that? Can you describe it in more detail? – Domino987 Aug 20 '21 at 20:45
  • Setting it on mount will trigger the watchPosition event unnecessarily early, I want it to be triggered manually by the user if needed. – Sam Aug 20 '21 at 20:48

1 Answers1

0

Figured out a solution using refs to break out of the closure.

Solution:

 function Map() {
    const watchRef = useRef();
    const isBoolRef = useRef(); // create a ref
    const [isBool, setIsBool] = useState(false);   

    function init() {
      watchRef.current = navigator.geolocation.watchPosition(success, error);
    }

    // no need for useCallback
    const success = (pos) => { 
      if(isBoolRef.current) {
        // do something...
        return;
      }
      // do something else...
    }
  
    function updateStateHandler() {
      setIsBool(true);
    }

    useEffect(() => {
      isBoolRef.current = isBool; // this will return the updated value inside the callback
    }, [isBool])

    return // jsx...  
}
Sam
  • 375
  • 1
  • 5
  • 15