2
\$\begingroup\$

I'm not really sure if the following solution is the best fit, and I would like to know best practices when manipulating state and/or Ajax isomorphic fetch requests, in this case, in intervals.

Users Module

import { createAction, handleActions } from 'redux-actions'
import { api } from '../utils/api'

export const REPORT_POSITION_INTERVAL = 'REPORT_POSITION_INTERVAL'
export const CLEAR_POSITION_INTERVAL = 'CLEAR_POSITION_INTERVAL'
export const POSITION_UPDATED = 'POSITION_UPDATED'

export const positionUpdated = createAction(POSITION_UPDATED, (value) => value)
export const setReportPositionInterval = createAction(REPORT_POSITION_INTERVAL, (interval) => interval)
export const clearPositionInterval = createAction(CLEAR_POSITION_INTERVAL)

export const reportPosition = () => {
  return (dispatch, getState) => {
    if (!navigator.geolocation) {
      return
    }

    function success (position) {
      var latitude = position.coords.latitude
      var longitude = position.coords.longitude

      if (getState().user.userId !== null && getState().user.currentCheckup !== null) {
        var data = {
          lat: latitude,
          lng: longitude,
          user_id: getState().user.userId,
          vehicle_id: getState().user.currentCheckup.vehicle_id
        }
        api(dispatch, getState, '/api/positions/add', 'POST', data, positionUpdated)
      }
    }

    function error () {
      alert('error')
    }

    if (getState().user.currentCheckup !== null) {
      var options = {enableHighAccuracy: true}
      navigator.geolocation.getCurrentPosition(success, error, options)
    }
  }
}

export const reportPositionPeriodically = () => {
  return (dispatch, getState) => {
    dispatch(setReportPositionInterval(setInterval(() => {
      dispatch(reportPosition())
    }, 10000)))
  }
}


export const actions = {
  reportPositionPeriodically,
  clearPositionInterval
}


export default handleActions({
  [REPORT_POSITION_INTERVAL]: (state, { payload }) => {
    return {
      ...state, reportPositionInterval: payload
    }
  },
  [CLEAR_POSITION_INTERVAL]: (state, { payload }) => {
    var clearedInterval = clearInterval(state.reportPositionInterval)
    return {
      ...state, reportPositionInterval: clearedInterval
    }
  },
  [POSITION_UPDATED]: (state, { payload }) => {
    return state
  }
}, {reportPositionInterval: null})

The reportPositionPeriodically action is called from the view.

The reportPositionPeriodically() passes along a setInterval arrow function to setReportPositionInterval which keeps the interval in the state and runs reportPosition().

reportPosition calls a function named api() imported from utils.

Utils API

import fetch from 'isomorphic-fetch'
import config from 'config'
export const api = (dispatch, getState, endpoint, method, data, success)
...
fetch(config.api_host + endpoint + query, params).then((response) => {
    dispatch(loaderActions.finished())
    return response.json()
}).then((value) => {
    if (value.message) {
        dispatch(loaderActions.fetchError(value.message))
    }
    if ((value.code !== undefined && value.code >= 200 && value.code <= 300) || (value.success !== undefined && value.success)) {
        dispatch(success(value))
    }
})

To clear the timer and stop the fetch requests, I perform a call to clearPositionInterval() which runs clearInterval on the interval in the state.

I find redux very hard and I'm having a hard time finding out how to do things properly.

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

Your code is really nice, and your use of generated property keys is really good.

There's a few things you can improve upon:

import { api } from '../utils/api'
export const api = (dispatch, getState, endpoint, method, data, success)

If you're only exporting one item from the module, you should just export it as default:

import api from '../utils/api'
export default const api = (dispatch, getState, endpoint, method, data, success)

This is when you would use an enum type:

export const REPORT_POSITION_INTERVAL = 'REPORT_POSITION_INTERVAL'
export const CLEAR_POSITION_INTERVAL = 'CLEAR_POSITION_INTERVAL'
export const POSITION_UPDATED = 'POSITION_UPDATED'

You could use the ES6 Map or enumify on npm

\$\endgroup\$
1
\$\begingroup\$

It looks OK, but I would just return the promise from the api module, and handle the errors, success and so on in the place where redux lives.. namely in reportPositionPeriodically

This way your API-module will be smaller and more reusable, for instance:

I find redux very hard and I'm having a hard time finding out how to do things properly.

you could replace it later, but the api methods would still work ;) If you do so, you also have a better overview of your state and whats happening to your store

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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