Efficient way to request back-end for data on input change

Viewed 501

This is more of a suggestion asking kind of question! I have a searchbox that user can type stuff in and the get a list of suggestion to choose from. I am using react, axios for data fetching and redux-saga for state managing.It is basically look like this:

handleChange(stringValue){
    this.setState({
        inputValue : stringValue
    });
    callServer(stringValue);
}

Now, everything works fine but the problem is that sending all those requests and handling the incoming response and changing state seems unnecessary because user doesn't stop to look at the suggestions in every char he types. I am looking for a way to only ask for suggestions when i know user is done fast typing. What i am thinking of doing looks like this :

handleChange(stringValue){
    clearTimeOut(this.callerTimer);
    this.callerTimer = null;
    this.callerTimer = setTimeOut(function(){
        this.callServer(stringValue);
        this.callerTimer = null;
    }.bind(this),300)
    //i consider 300ms as the average time it takes people to stop typing and think
}

This works but i don't have a good feeling about it. So do you guys know any other clean and less timerly way to do what i want? is there any way to handle this in my saga effect or maybe an inbuilt time threshold thing in inputs that i am not aware of?

2 Answers

You want debounce functionality.

Basically it limits the rate at which a function can fire. So it waits a few ms before firing the event kind of like the user stopping the writing process.

Check this snippet

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
 var timeout;
 return function() {
  var context = this, args = arguments;
  var later = function() {
   timeout = null;
   if (!immediate) func.apply(context, args);
  };
  var callNow = immediate && !timeout;
  clearTimeout(timeout);
  timeout = setTimeout(later, wait);
  if (callNow) func.apply(context, args);
 };
};

// This will apply the debounce effect on the keyup event
// And it only fires 500ms or half a second after the user stopped typing
$('#testInput').on('keyup', debounce(function () {
  alert('typing occurred');
  $('.content').text($(this).val());
}, 500));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="testInput" />

<p class="content"></p>

Check this codesandbox for React solution

https://codesandbox.io/embed/green-meadow-16r3p?fontsize=14

Basically now it's up to you. Set your own time in ms and you're good to go. There is no need to install any additional dependencies to your project. Lodash has a debounce function but you don't want to install all of lodash just for one function.

I highly recommend using debounce from lodash: https://lodash.com/docs/4.17.11#debounce

From the docs:

Creates a debounced function that delays invoking func until after wait milliseconds have elapsed since the last time the debounced function was invoked.

Therefore you pass your request function to debounce, so you limit the number of requests to your server.

Related