pburtchaell / redux-promise-middleware

Enables simple, yet robust handling of async action creators in Redux
https://pburtchaell.gitbook.io/redux-promise-middleware/
MIT License
1.98k stars 188 forks source link

Payload is empty on the FULFILLED action and it shouldn't #141

Closed golinmarq closed 7 years ago

golinmarq commented 7 years ago

Problem

The FULFILLED action (I call it SUCCESS) doesn't send any data in the payload. I'm using axios and normalize to flat my responses. I created a function called fetchData in my api folder, so when I call the fetchOrders action it should run this function, but instead when I get the SUCCESS action, the payload doesn't exist. What can be wrong? Should I define another parameter in the payload? The code example is bellow

Version Number

Redux promise middleware v4.2.0 Axios v0.15.0 Normalizr v3.0.2

Code Example

api.js

import axios from 'axios';
import { normalize } from 'normalizr';
import { camelizeKeys } from 'humps';

const API_ROOT = 'http://localhost:3000/api';

export const fetchData = (endpoint, schema) => {
  const fullUrl = (endpoint.indexOf(API_ROOT) === -1) ? API_ROOT + endpoint : endpoint;

  return axios.get(fullUrl)
    .then(response => {        
        if (!response.data.success) {
          return Promise.reject(response.data);
        }
        const camelizedJson = camelizeKeys(response.data.data);
        const lastFecth = Date.now();
        return Promise.resolve(Object.assign({},
          normalize(camelizedJson, schema), 
          { lastFecth }
        ));
      }
    );
}

order.js: file with orders actions

import * as api from '../api';
import * as Schemas from '../api/schema';
import { addEntity, updateError } from './';

// ... other actions 

export const FETCH_ORDERS = 'FETCH_ORDERS';

const fetchOrders = ()=>(dispatch)=>(dispatch({
    type: FETCH_ORDERS,
    payload: {
            promise: api.fetchData('/orders',Schemas.ORDER)
                .then((response)=>(dispatch,action)=>{
                dispatch(addEntity(response.entities));
                })
                .catch((error)=>(updateError(error)))
            }
}));

Expected Behavior

When I call FETCH_ORDERS action, it should call the API using the api.fetchData function. This returns a promise with the data in it. If it successful it should update the state, otherwise it should catch the error.

Actual Behavior

The action fulfilled is reached but without payload, the reducer sends an error because of it and the catch of the promise is fired

pburtchaell commented 7 years ago

The action fulfilled is reached but without payload...

I have not used Axios before, but it is a promised based library, meaning it will return a promise. You don't need to call Promise.reject and Promise.resolve, like you are now. That just creates another layer of abstraction where one promise is returning a second promise. This is likely why the fulfilled action is dispatched but without a payload.

export const fetchData = (endpoint, schema) => {
  const fullUrl = (endpoint.indexOf(API_ROOT) === -1) ? API_ROOT + endpoint : endpoint;

  return axios.get(fullUrl)
    .then(response => {        
        if (!response.data.success) {
          throw response.data;
        }

        const camelizedJson = camelizeKeys(response.data.data);

        const lastFecth = Date.now();

        return Object.assign({},
          normalize(camelizedJson, schema), 
          { lastFecth }
        );
      }
    );
}

Try making this change and let me know if that resolves your issue.

golinmarq commented 7 years ago

Thanks @pburtchaell ! That recommendation works really well.

Also I delete the dispatch(addEntity(response.entities)); in then and change the reducer to add an entity according to action payload.