Async actions in Redux

47,030

Solution 1

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.

Solution 2

The accepted answer is either outdated, wrong or over-convoluted. Here are the docs on the compose subject:

http://redux.js.org/docs/api/compose.html

so we can do it like this instead:

import {createStore, combineReducers, compose, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';

const reducer = combineReducers({
    user: userReducer,
    items: itemsReducer
});


// here is our redux-store
const store = createStore(reducer,
    compose(applyMiddleware(thunk))
);

Solution 3

I believe it is possible to have a working solution without using the compose function too. Based on the documentation from the GitHub repo for redux-thunk

Solution works for redux-thunk: ^2.0.0

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

export function configureStore(initialState = {}) {
  return createStore(
    duedates,
    initialState,
    applyMiddleware(thunk)
  );
}
Share:
47,030
Pablo
Author by

Pablo

Updated on December 16, 2020

Comments

  • Pablo
    Pablo over 3 years

    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;