I need to perform a Search when user stops typing.I know I am supposed to use setTimeout() . But with Reactjs I cant find how it works. Can
This library (use-debounce) is nice and simple.
Setup
yarn add use-debounce
or
npm i use-debounce --save
Usage sample from documentation
import React, { useState } from 'react';
import { useDebounce } from 'use-debounce';
export default function Input() {
const [text, setText] = useState('Hello');
const [value] = useDebounce(text, 1000);
return (
<div>
<input
defaultValue={'Hello'}
onChange={(e) => {
setText(e.target.value);
}}
/>
<p>Actual value: {text}</p>
<p>Debounce value: {value}</p>
</div>
);
}
Things that I liked at this moment, things could be different in future!:
- Easy to setup & use
- Less Boilerplate code
- Modest ratings (~1K) and usage (npm - 200K downloads/Week)
- Supports timeout, MaxWait and other features
Problem of Typeahead library https://twitter.github.io/typeahead.js/
Since the case here is simple, I can use a quick and dirty solution:
onChange: (event) ->
if @_timeoutTask?
clearTimeout @_timeoutTask
@_timeoutTask = setTimeout (=>
@sendToParent event.target.value
clearTimeout @_timeoutTask
), 5000
In this way, the task will be triggered 5s after input event. If new event happens, the old task will be cancelled and a new task is scheduled, then it's another 5s to wait.
The difference in React is the where to store the computation state like _timeoutTask
. The file scope, the component state, or the component instance.
Since _timeoutTask
is component level, it should be be store globally. And it does not affect rendering, so not in component state too. So I suggest attaching it to component instance directly.
User lodash javascript library and use [_.debounce][1]
changeName: _.debounce(function (val) {
console.log(val)
}, 1000)
I think we can do it in a more simpler and cleaner manner, without abrupting the state parameter which calls the complete component life cycle like this:
constructor(props) {
super(props);
//Timer
this.typingTimeout = null;
//Event
this.onFieldChange = this.onFieldChange.bind(this);
//State
this.state = { searchValue: '' };
}
/**
* Called on the change of the textbox.
* @param {[Object]} event [Event object.]
*/
onFieldChange(event) {
// Clears the previously set timer.
clearTimeout(this.typingTimeout);
// Reset the timer, to make the http call after 475MS (this.callSearch is a method which will call the search API. Don't forget to bind it in constructor.)
this.typingTimeout = setTimeout(this.callSearch, 475);
// Setting value of the search box to a state.
this.setState({ [event.target.name]: event.target.value });
}
<div className="block-header">
<input
type="text"
name="searchValue"
value={this.state.searchValue}
placeholder="User Name or Email"
onChange={this.onFieldChange}
/>
</div>
you can just use the debounce from lodash or simulate using setTimeout.
import React, {Component, PropTypes} from 'react';
export default class SearchBox extends Component {
constructor(props){
super(props);
this.state={ name:" "}
this.timeout = null;
}
changeName = (event) => {
clearTimeout(timeout);
if(timeout){
setTimeout((event)=> this.setState({name: event.target.value}), 200)
}
}
sendToParent = () => {
this.props.searching(this.state.name);
}
render() {
return (
<div>
<input type="text" placeholder='Enter name you wish to Search.' onChange={this.changeName} />
</div>
);
}
}
I used the debounce function of lodash
onChangeSearchInput = (evt)=> {
this.debouncedSearch(evt.target.value);
};
debouncedSearch = debounce(function (query) {
this.setState({query});
}, 1000);
Somewhere in my render method i have this input field
<input
type='text'
onChange={this.onChangeSearchInput}
className='uk-input'
placeholder={'search by name or email...'}
/>