Reputation: 2351
I am trying to fetch the suggestion for input field in my react component. I trigger onChange event on this input field which then makes an api call and fetched the relevant content.
This is how I am doing it
<span>
<input type="text" placeholder="Add tag" list="languages" id='tags-input-field'
className={`addtag-input ${this.state.showAddTagInputArray.findIndex(x => x === item.id) !== -1 ? "" : "hidden"}`}
onChange={this.searchTags.bind(this)}
/>
<datalist id='languages'>
{this.state.existingTags && this.state.existingTags.map((item,i)=>{
return <option value= {item.name} />
})}
</datalist>
</span>
And this is "searchTags" function
searchTags(){
let req = fetch(url + document.getElementById("tags-input-field").value,
{
method: "GET",
headers: {
"Authorization": "Token " + this.props.token_reducer.token,
"content-type": "application/json"
}
})
req.then(response => response.json()
).then(response => {
console.log(response)
this.setState({existingTags:response})
})
}
Problem: Problem with this approach is, searchTags() gets fired for each letter I press. Suppose I type 10 letters very fast then 10 requests starts and this is hanging my system. How should I approach this problem?
Upvotes: 0
Views: 1141
Reputation: 1601
This is a very common problem with search inputs. The simplest solution that covers the common use cases is to debounce the call.
constructor () {
this.searchTags.bind(this);
this.debouncedSearch = this.debounce(this.searchTags, 300);
}
debounce = (func, wait = 100) => {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(this, args);
}, wait);
};
};
// in render
onChange={this.debouncedSearch}
Lodash also has a great off-the-shelf debounce.
You also need to add a key to each list item since you are rendering a list. Don't use index as your key, choose a unique identifier.
<datalist id='languages'>
{this.state.existingTags && this.state.existingTags.map((item,i)=>{
return <option key={item.id} value= {item.name} />
})}
</datalist>
Upvotes: 0
Reputation: 64687
You can delay the ajax request using something like setTimeout(fetch, n)
, and clear the timeout on each key press. This causes it to only search after they have stopped typing for at least n
milliseconds.
this.state = {
searchTimeout: false
}
searchTags(){
clearTimeout(this.state.searchTimeout);
let searchTimeout = setTimeout(function() {
let req = fetch(url + document.getElementById("tags-input-field").value,
{
method: "GET",
headers: {
"Authorization": "Token " + this.props.token_reducer.token,
"content-type": "application/json"
}
})
req.then(response => response.json()
).then(response => {
console.log(response)
this.setState({existingTags:response})
})
}.bind(this), 500);
this.setState({searchTimeout});
}
Upvotes: 1