0

I have a react app which shows the users location on map using react-leaflet. I used navigator.geolocation to get the position and sets it to the userData state when user allows access. Sometimes it is showing it on map but sometimes it is returning undefined.

redux-action :

export const getUserData = () => {
    return async (dispatch) => {
            if(navigator.geolocation) {
                navigator.geolocation.watchPosition((position) => {
                   dispatch({
                       type: FETCH_USER_DATA,
                       payload: position.coords
                   })
               })
        } else {
            alert('Unable to get location')
        }
    }
}

reducer :

export const rootReducer = (state = initialState, action) => {
    switch (action.type) {
        case FETCH_IP_LOCATION:
            return {
                ...state,
                ipLocation: action.payload,
                isLoading: false,
            }
        case FETCH_USER_DATA:
            return {
                ...state,
                userData: action.payload,
                isLoading: false,
            }
    }
}

Component which renders map :

import React from 'react';
import '../styles/MapComponent.css';
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
import { useEffect } from 'react';
import { getUserData } from '../redux/action/';
import { useDispatch, useSelector } from 'react-redux'
 
const MapComponent = () => {
    const dispatch = useDispatch()
    const isLoading = useSelector((state) => state.isLoading)
    const coord = useSelector((state) => state.userData)
 
    useEffect(() => {
       dispatch(getUserData())
    }, [])

  return (
    <MapContainer center={[coord.latitude, coord.longitude]} zoom={12}>
      <TileLayer
        attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      />
      <Marker position={[coord.latitude, coord.longitude]}>
        <Popup>
          A pretty CSS3 popup. <br /> Easily customizable.
        </Popup>
      </Marker>
    </MapContainer>
  
  )
}

export default MapComponent

1 Answer 1

0

Its better to keep the navigator logic outside redux and once you get the data you can dispatch them.

useEffect(() => {
    if (navigator?.geolocation) {
      navigator.geolocation.getCurrentPosition((location) => {
        if (location) dispatch(getUserData(location.coords));
      });
    }
  }, []);
  • Now in the first place you have to provide some coords to initialize the leaflet map as userData is undefined and not render the marker for the same reason

  • After you receive the data you will need an extra comp to change the maps view as center prop is immutable. No need to pass the center as you have that info on redux so you can consume it from there.

    function ChangeView() {
       const coords = useSelector((state) => state.root.userData);
    
       const map = useMap();
       map.setView([coords.latitude, coords.longitude], zoom);
    
       return null;
     }
    

In the following demo you can see all the pieces work together using redux-toolkit.

1
  • Yes, I tried it without redux, now working thanks.
    – Saidamir
    Commented Feb 22, 2022 at 14:17

Not the answer you're looking for? Browse other questions tagged or ask your own question.