Async actions in Redux

Pablo picture Pablo · Feb 21, 2016 · Viewed 46.9k times · Source

I have a React App, I need to make an ajax call (in order to learn) to a online service (async) with Redux.

This is my store:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import duedates from './reducers/duedates'


export default applyMiddleware(thunk)(createStore)(duedates);

This is the actions:

import rest from '../Utils/rest';

export function getDueDatesOptimistic(dueDates){
    console.log("FINISH FETCH");
    console.log(dueDates);
    return {
        type: 'getDueDate',
        dueDates
    }
}

export function waiting() {
    console.log("IN WAIT");
    return {
        type: 'waiting'
    }
}


function fetchDueDates() {
    console.log("IN FETCH");
    return rest({method: 'GET', path: '/api/dueDates'});
}

export function getDueDates(dispatch) {
    console.log("IN ACTION");
    return fetchDueDates().done(
        dueDates => dispatch(getDueDatesOptimistic(dueDates.entity._embedded.dueDates))
    )
}

And this is the reducer:

export default (state = {}, action) => {
  switch(action.type) {
    case 'getDueDate':
        console.log("IN REDUCER")

        return state.dueDates = action.dueDates;
    default:
        return state
  }
}

I dont get what I'm doing wrong. The action is being called perfectly from the component. But then I get this error:

Error: Actions must be plain objects. Use custom middleware for async actions.

I guess I'm using wrong the react-thunk middleware. What am I doing wrong?

EDIT

Now the action is calling to the reducer, but the reducer, after changing state, is not re-running the render method

    case 'getDueDate':
        console.log("IN REDUCER")

        return state.dueDates = action.dueDates;

Answer

rishat picture rishat · Feb 21, 2016

I think you should be using compose function, so it's like

import {
  createStore,
  applyMiddleware,
  compose
} from 'redux';
import thunk from 'redux-thunk';
import duedates from './reducers/duedates'

export default compose(applyMiddleware(thunk))(createStore)(duedates);

Thunk allows an action creator to return a function instead of plain-object, so you use it like

export function getDueDates() {
  return dispatch => {
    console.log("IN ACTION");
    fetchDueDates().done(
      dueDates => dispatch(getDueDatesOptimistic(dueDates.entity._embedded.dueDates))
    )
  };
}

You were returning a Promise object, that was one part of the problem. Another part was that redux-thunk hasn't been properly applied. I bet compose should get the problem solved.