1

I send request to server everytime user types something. I use debounce for the 400ms delay:

type = debounce((text) => {          
      this.props.actions.loadInfo(text) 
  }, 400);

When I type something, stop and start again and repeat it, several requests are send and I receive irrelevant data. I use promises:

export const loadInfo = (text) => dispatch => {
  loadData(text).then(result => {
    dispatch(showUserData(result));
  });
};

export const loadData = async (text) => {
  const tabData = await axios.get(`url&query=${text}`);
  return tabData;
}

I need somehow cancel previous request if user sends the new one(when he typed something), what is the best way to do that? I expected debounce will help me but not. I use axios. This is not duplicate of questions here, I checked provided solutions but thet don't help me

rick1
  • 946
  • 3
  • 15
  • 31
  • https://stackoverflow.com/a/26735236/2630817 – Just code Nov 19 '18 at 09:51
  • 1) I use axios 2) that won't work as I tried in other case that variant – rick1 Nov 19 '18 at 09:52
  • again, there is no correct answer – rick1 Nov 19 '18 at 09:54
  • @rick1 What do you mean by 'correct'? I believe my own answer is correct one, otherwise I wouldn't link it. – Estus Flask Nov 19 '18 at 09:55
  • creator of the question didn't mark it as correct so it didn't help him. I will check your variant, maybe it will work – rick1 Nov 19 '18 at 09:57
  • There's a working demo. The poster abandoned the question and didn't provide any feedback, which isn't a very good practice on SO but it's quite common. – Estus Flask Nov 19 '18 at 10:01
  • for me it is unclear what is this._fetchDataCancellation, I do not see such method in the demo that you send. – rick1 Nov 19 '18 at 10:02
  • It's cancellation object, it's assigned, `this._fetchDataCancellation = CancelToken.source()`. Consider addressing other users with `@`, otherwise they don't receive notifications. – Estus Flask Nov 19 '18 at 10:05
  • @estus still I do not uderstand why do you use this. – rick1 Nov 19 '18 at 10:07
  • in my case it isn't work as I return data in other place. CHeck my code above – rick1 Nov 19 '18 at 10:09
  • The answer provides this information. It's Axios cancellation API https://github.com/axios/axios#cancellation . Storing cancellation object allows to cancel a request. Otherwise you wouldn't be able to do that. – Estus Flask Nov 19 '18 at 10:28
  • I made as you mention but it isn't hwlp me. I think I made mistake in adding your solution to my code @estus – rick1 Nov 19 '18 at 10:29
  • It won't work in your case because you debounce `props.actions.loadInfo`. It cannot cancel a request in one place and not cancel it in another place. If you need to debounce globally, debounce `loadData` where you have access to axios request, not functions that use it. If you don't need to debounce globally then you need to change the way data is processed in your app. It's specific to React and Redux and the way you use them, while the question didn't focus on that and didn't have relevant tags. – Estus Flask Nov 19 '18 at 10:29
  • I do not copied debouce as in your example, I use debounce in the typing function @estus – rick1 Nov 19 '18 at 10:31
  • @estus can you provide me with the example that will pass to my code? I cannot integrte xode from your demo in my code – rick1 Nov 19 '18 at 10:33
  • You won't be able to make it the way you showed in the question for the reasons I mentioned. As I said, you need to debounce `loadData`, not `props.actions.loadInfo`. If you have problems with this approach, consider reasking a new question with https://stackoverflow.com/help/mcve that covers all technologies in use - Axios, React, Redux. A working demo of your current attempt will increase chances to solve the problem because it's complex and likely requires to change how data is processed with Redux. I cannot provide an example for now because I don't know how your app works. – Estus Flask Nov 19 '18 at 10:35
  • 1
    In case this is solved by debouncing `loadData`, it should be something like https://0bin.net/paste/VVzDKApYNqisbwKU#9fOWpDXYKrfvKNyZhL9lPinBDxUNaI2kocTHXqsKCEJ . Hope this helps. Also noticed that demo was wrong in the post I linked, fixed it, https://stackblitz.com/edit/react-ecsbrz . Also was wrong link in this comment, updated it, sorry for that. – Estus Flask Nov 19 '18 at 11:10
  • @estus thanks, it works. It would be great to attach this as an aswer – rick1 Nov 20 '18 at 17:50

2 Answers2

0

The problem is similar to this one. Axios cancellation API can be used to cancel old requests. This should be done in a function that does a request (loadData) and has direct access to Axios, it may be also debounced:

let cancelObj;

export const loadData = debounce((text) => {
  if (cancelObj) {
      this.cancelObj.cancel();
    }

  cancelObj = CancelToken.source();

  return axios.get(`url&query=${text}`, {
    cancelToken: this._fetchDataCancellation.token
  }).catch(err => {
    // request wasn't cancelled
    if (!axios.isCancel(err))
      throw err;
  });
}, 200);

Since Redux is used, other solutions may involve it, they depend on how Redux is used.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
0

Even I tried to use debounce function in my code but the problem is that if user types very fast stop and then again start typing, in that case, your input values get updated and UI get distorted, to avoid this I used XMLHttpRequest and its abort() to cancel the previous calls, if calls do not succeed then it will be canceled,

you can try this solution, https://stackoverflow.com/a/55509957/9980970

Serenity
  • 35,289
  • 20
  • 120
  • 115