React Redux adding extra field for action promises to return differently
I want to add the isLoading flag to my action generator and reset it to my reducer. Initially without a flag, my code works and the action looks like this
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 the 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;
}
}
As you can see the object is returned ok and I can get my list via action.payload.data.data.results
Please note that I am using redux promise as my promise fulfillment middleware.
As soon as I change my action to the following and run the code, I receive my payload (as shown in the image below) as a promise, not a returned object
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,
}
}
Why is it just adding another variable causing this problem?
Redux Promise and Redux Promise Middleware are Flux Standard Action (FSA) compliant . Add a key meta
to the action and assign key / value pairs in it.
Related question / answer: fooobar.com/questions/1628491 / ...
From FSA documentation:
The optional meta property MAY be any value type. It is for any additional information that is not part of the payload.
Try this how it is done with redux-thunk, so I hope it looks like redux-prom-middleware. Also see what is returned:
all: action.payload
in your gearbox
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
});
}
I think the cleanest and most responsive 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, it assumes you are using redux-thunk. The main idea is to make the reducer manage the state, including the setting isLoading
, this way you can update your component while the request state changes ... The code above is not ready for copy / paste, it is meant to carry over the idea.