Search code examples
reactjsreduxgeolocationreact-reduxredux-thunk

Redux thunk wont update with response from async function


I have been following a guide to setup redux-thunk so I can fetch a users geolocation and then dispatch and update state. However, every time I attempt to dispatch the action with response data, it just sets the data to null.

When I attempt to simulate an API call with a timeout and set some random values, it works without a problem.

geoLocationActions.js

export function geoLocationActions() {
   return dispatch => {
    const geolocation = navigator.geolocation;
    geolocation.getCurrentPosition((position) => {
        console.log(position.coords);
        dispatch({
            type: 'FETCH_USER_LOCATION_SUCCESS',
            payload: position
        });
    });
  } 
};

MapContainer.js

import React from "react";
import { geoLocationActions } from '../../../actions/geoLocationActions';
import { connect } from 'react-redux';

class MapContainer extends React.Component {

    componentWillMount() {
        this.props.geoLocationActions();
    }

    render() {
        return (
            <div>
                <p>Fetching location...</p>
            </div>
        );
    }
}

// update current geolocation state
const mapDispatchToProps = (dispatch) => {
    return {
        geoLocationActions: () => dispatch(geoLocationActions())
    };
}

const mapStateToProps = (state) => {
    return {
        state: state
    };
};

export default connect(mapStateToProps, mapDispatchToProps)(MapContainer);

reducers.js

case 'FETCH_USER_LOCATION_SUCCESS':
        return {
            ...state,
            userLocation: action.payload
        }

store.js

import { createStore, combineReducers, applyMiddleware, compose } from 

'redux';
import reducer from '../reducers/reducers';
import reduxThunk from "redux-thunk";

const rootReducer = combineReducers({
    state: reducer
});

export const store = createStore(
    rootReducer,
    compose(
        applyMiddleware(reduxThunk),
        window.devToolsExtension ? window.devToolsExtension() : f => f
    )
);

Solution

  • It turns an HTML5 Geoposition object. You need to convert it to a regular object that can be serialized with JSON.stringify. You can use this method:

    const geopositionToObject = geoposition => ({
      timestamp: geoposition.timestamp,
      coords: {
        accuracy: geoposition.coords.accuracy,
        latitude: geoposition.coords.latitude,
        longitude: geoposition.coords.longitude
      }
    })
    

    Update your geoLocationActions.js like this:

    export function geoLocationActions() {
       return dispatch => {
        const geolocation = navigator.geolocation;
        geolocation.getCurrentPosition((position) => {
            const positionObj = geopositionToObject(position)
            console.log(positionObj);
            dispatch({
                type: 'FETCH_USER_LOCATION_SUCCESS',
                payload: positionObj
            });
        });
      } 
    };
    

    You can have a look at my repo to see the same code.