5

I want to add a isLoading flag to my action generator and reset it at my reducer. Initially without the flag, my code works and the action looks like the following

export function getList() {
    const FIELD = '/comics'
    let searchUrl = ROOT_URL + FIELD + '?ts=' + TS + '&apikey=' + PUBLIC_KEY + '&hash=' + HASH;
    const request = axios.get(searchUrl)
    return {
        type: FETCH_LIST, 
        payload: request,
    }
}

and reducer looks like

const INITIAL_STATE = { all: [], id: -1, isLoading: false };

export default function (state = INITIAL_STATE, action) {
    switch (action.type) {
        case FETCH_COMIC_LIST: 
            console.log('reducer action =', action, 'state =', state)
            return {
                ...state, 
                all: action.payload.data.data.results,
                isLoading: false
            }
        default:
            return state;
    }
}

Good result

As you can see, the object returns fine and I can get my list via action.payload.data.data.results

Note that I am using redux promise as my middleware to handle the promise.

As soon as I changed my action to the following and re run the code I get my payload (as shown in image below) to be a Promise rather than the object that was returned

export function getComicList() {
    const FIELD = '/comics'
    let searchUrl = ROOT_URL + FIELD + '?ts=' + TS + '&apikey=' + PUBLIC_KEY + '&hash=' + HASH;
    const request = axios.get(searchUrl)
    return {
        type: FETCH_COMIC_LIST, 
        isLoading: true, 
        payload: request,
    }
}

isLoading added

Why is simply adding another variable causing this problem??

ErnieKev
  • 2,831
  • 5
  • 21
  • 35

3 Answers3

4

Redux Promise and Redux Promise Middleware are both compliant with Flux Standard Action (FSA). Add a meta key to the action and assign your key/value pairs within it.

Related question/answer: https://stackoverflow.com/a/35362148/4290174

From the FSA documentation:

The optional meta property MAY be any type of value. It is intended for any extra information that is not part of the payload.

Patrick Burtchaell
  • 4,112
  • 1
  • 14
  • 25
Lush
  • 282
  • 2
  • 11
-1

Try this - its how its done using redux-thunk - so I'm hoping its similar to redux-promise-middleware. Also see what is returned from:

all: action.payload in your reducer

    export function getList() {
        const FIELD = '/comics'
        let searchUrl = ROOT_URL + FIELD + '?ts=' + TS + '&apikey=' + PUBLIC_KEY + '&hash=' + HASH;

        // return a promise that the middleware should handle
        // return response or error from promise
        return axios.get(url)
          .then((response) => {
            type: FETCH_LIST,
            isLoading: true, 
            payload: response
          }).error((response) => {
            //handle error
          });
    }
Spencer Bigum
  • 1,811
  • 3
  • 17
  • 28
  • This is not correct. To solve this question, simply use the `meta` field, as mentioned in the correct answer: https://stackoverflow.com/a/48371940/2476275 – Patrick Burtchaell Apr 22 '18 at 14:39
  • it would be nice if Redux gave you a warning or something of what not to put in the response, because I would have never known otherwise. – Spencer Bigum Apr 27 '18 at 22:11
  • You're right, that would be a nice way to solve this problem, as I've noticed people are tripped up by it. The `meta` field isn't, however, a Redux requirement, but rather a standard that Redux middleware can opt to follow. Perhaps something for said middleware to consider. – Patrick Burtchaell Apr 29 '18 at 12:52
-1

I think the cleanest and most react-redux way is:

//types:
const FETCH_LIST_START = "…";
const FETCH_LIST_SUCCESS = "…";
const FETCH_LIST_ERROR = "…";

//action
const loadList = url => dispatch => {
  dispatch({type: FETCH_LIST_START });

  fetch(url)
    .then(res => {
      if (res.status !== 200) throw new Error('load failed');
      dispatch({ 
        type: FETCH_LIST_SUCCESS,
        payload : { res } }
      })

    )
    .catch(err => dispatch({ 
      type: FETCH_LIST_ERROR, 
      payload: { error } })
    );
};

//REDUCER
case: FETCH_LIST_START:
  return Object.assign({}, state, { isLoading: true });
  break;
case: FETCH_LIST_SUCCESS:
  return Object.assign({}, state, { 
     isLoading: false, 
     data: action.payload.res
  });
  break;
case FETCH_LIST_ERROR:
  …
  break;

So that assumes you are using redux-thunk. The basic Idea is to make your reducer handle the state, including setting the isLoading thing, that way, you can update your component while the request state changes… The code above is not copy/paste ready, it is meant to transport the idea.

philipp
  • 15,947
  • 15
  • 61
  • 106
  • Few questions...1. This is using redux-thunk middleware right? 2. do you know why my original code get messed up when isLoading is added? – ErnieKev Apr 28 '17 at 07:24
  • With in the context of the question (which uses Redux Promise Middleware), this is not correct. To solve this question, simply use the `meta` field, as mentioned in the correct answer: https://stackoverflow.com/a/48371940/2476275 – Patrick Burtchaell Apr 22 '18 at 14:39