Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can we cancel out api response when the react router is changed?

I am using same form and same state in redux for add and edit. When I call api for fetching data for edit and we change our router to add form before the response arrives. All the form datas will be auto filled for add item since i am using same state for both add and edit. Is there any way to prevent this from happening?

my action creator:

fetchById: function (entity, id) {
        return function (dispatch) {
            dispatch(apiActions.apiRequest(entity));
            return (apiUtil.fetchById(entity, id).then(function (response) {
                    dispatch(apiActions.apiResponse(entity));
                    dispatch(actions.selectItem(entity, response.body));
            } 
       }
}

As response is late then selectItem is dispatched late. And when I open form for adding item then this form is filled with this data from response.

like image 513
Bishal Shrestha Avatar asked Apr 15 '16 01:04

Bishal Shrestha


Video Answer


2 Answers

Thunks get both dispatch and getState as arguments.

If you keep the current route somewhere in your state, you can check in the API callback whether you’re still on the same page with getState().routing.path or something like this, and return if it has changed since the API call started.

If you don’t keep the current route in the state, you can instead read this.context.router in your component (don’t forget to define contextTypes to get it!) and pass it to the action creator. The action creator can then use router.isActive() to check whether we’re still on the same path before and after the request.

Finally, you can just not use the same state for editing and adding an item. Your state shape can look like { drafts: { newItem: ..., 1: ..., 2: ... } } and you could keep the “add” form in drafts.newItem, and keep any “edit” form by the corresponding entity’s ID. This way they would never overwrite each other and, as a bonus, in-progress edits could be preserved, e.g. if you press “Back” and then go to the form again (depending on whether you want this in your UX of course).

like image 96
Dan Abramov Avatar answered Oct 11 '22 15:10

Dan Abramov


I saw this blog post the other day and I think the second part describes what you are looking for. You don't necessarily want to cancel the requests but ignore the responses.

Basically you want to create an outer reducer which will keep track of your async requests to the server with unique ids. Only if the request id is in the list then allow it into the sub reducers.

When you switch page you will want to clear out this list of unique ids.

Lifted straight from the blog:

const initialState = [];

function update(state = initialState, action) {
  const { seqId } = action;

  if (action.type === constants.UNLOAD) {
    return initialState;
  }
  else if (seqId) {
    let newState;
    if (action.status === 'start') {
      newState = [...state, seqId];
    }
    else if (action.status === 'error' || action.status === 'done') {
      newState = state.filter(id => id !== seqId);
    }

    return newState;
  }

  return state;
}

and then restrict the sub reducers:

let store = createStore((state, action) => {
  if (action.seqId &&
      (action.status === 'done' || action.status === 'error') &&
      state &&
      state.asyncRequests.indexOf(action.seqId) === -1) {
    return state;
  }
  return reducer(state, action);
});

Big shout out to James for this. Really nice solution and very well explained in his blog post.

like image 38
Clarkie Avatar answered Oct 11 '22 14:10

Clarkie