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?
source to share
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.
source to share
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
});
}
source to share
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.
source to share