skip to Main Content

I’m new in React and I would use the hook useGeolocation but it’s refresh all the times. So I isolate this hook in a component Location but I can’t access to the position of the user and send to my component MapWrapper to center the map.

import { useGeolocation } from "@uidotdev/usehooks";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { AlertCircle } from "lucide-react"
import { MapWrapper } from "../mapWrapper";
import React, { forwardRef, useEffect, useRef } from "react";

export const Home = () => {
    const refLatLong = useRef()

    useEffect(() => {
        console.log(refLatLong.current?.getAttribute('position'))
    }, []);

    return (
        <>
            <Location ref={refLatLong} />
            <MapWrapper position={refLatLong.current} />
        </>
    ) 
}

const Location = forwardRef((props, ref) => {
    const location = useGeolocation();
    if (location.loading) {
        return <>
            <Alert variant="destructive">
            <AlertCircle className="h-4 w-4" />
            <AlertTitle>Chargement...</AlertTitle>
            <AlertDescription>
                Vous devez accepter la géolocalisation
            </AlertDescription>
            </Alert>
        </>
    }
    
    if (location.error) {
        return <>
            <Alert variant="destructive">
                <AlertCircle className="h-4 w-4" />
                <AlertTitle>Chargement...</AlertTitle>
                <AlertDescription>
                    Activer les autorisations pour accéder à vos données de localisation
                </AlertDescription>
            </Alert>
        </>
    }

    return <div ref={ref} id="user-position" position={[location.latitude, location.longitude]}></div>

})

Could you tell me what is my error with the ref and if it’s the good solution.
Thanks a lot

2

Answers


  1. Chosen as BEST ANSWER

    Thank you, it's help me but the useCallback doesn't work correctly and the position continue to change every time useGeolocation() is refresh

    export const Home = () => {
    console.log('render Home')
    const [position, setPosition] = useState()
    
    const updatePosition = useCallback((position) => {
        setPosition((prevState) => {
            if(prevState !== position) {
                return position
            }
        })
    }, [])
    
    return (
        <>
            <Location onPositionLocated={updatePosition} />
            {position && <MapWrapper position={position} />}
        </>
    )
    }
    
    const Location = (({onPositionLocated}) => {
    console.log('render Location')
    const location = useGeolocation();
    
    useEffect(() => {
        if (!location.loading && !location.error) {
            onPositionLocated([location.latitude, location.longitude])
        }
    }, [location, onPositionLocated])
    
    if (location.loading) {
        return <>
            <Alert variant="destructive">
            <AlertCircle className="h-4 w-4" />
            <AlertTitle>Chargement...</AlertTitle>
            <AlertDescription>
                Vous devez accepter la géolocalisation
            </AlertDescription>
            </Alert>
        </>
    }
    
    if (location.error) {
        return <>
            <Alert variant="destructive">
                <AlertCircle className="h-4 w-4" />
                <AlertTitle>Chargement...</AlertTitle>
                <AlertDescription>
                    Activer les autorisations pour accéder à vos données de localisation
                </AlertDescription>
            </Alert>
        </>
    }
    })
    

  2. Two important things,

    The useEffect will be triggered only once, as your dependencies array is empty, this will cause that even if your ref is updated with the div you attached on Location component after render, it won’t be triggered again and thus you won’t be able to access the ref.current unless is already loaded.

    You can solve this issue by adding in your dependencies array the ref.current, by adding the dependency the useEffect will be triggered whenever the ref.current changes

    
        useEffect(() => {
            console.log(refLatLong.current?.getAttribute('position'))
        }, [refLatLong.current]);
    

    Another thing is that a ref update won’t trigger a re-render, so even if the ref.current has changed and now contains the div ref of Location your MapWrapper won’t be rendered with the updated value because the ref update didn’t triggered a Home re-render. In order to do that e.g, you would need to add a state in the Home and make the Location component to update it via a callback prop, something similar to:

    //Home component
    const [position, setPosition] = useState()
    
    const updatePosition = useCallback((position) => {
          setPosition(position)
    }, [])
    
        return (
            <>
                <Location ref={locationRef} onPositionLocated={updatePosition} />
        .....rest of code
    
    
    // Then Location component
    useEffect(() => {
          if (!location.loading && !location.error) {
            onPositionLocated({
               latitude: location.latitude, 
               longitude: location.longitude
          });
         }
    }, [location, onPositionLocated])
    

    Finally the MapWrapper will be able to receive the position via props

    You can find some info about refs here

    Hope it helps

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search