Search After Stop Typing React Component
In this post I’m going to go through how to implement a search criteria component that only invokes the search in a calling component after the user has stopped typing.
So, we have the following search criteria component that invokes the search on a submit button at the moment:`// SearchCriteria.tsx
// SearchCriteria.tsx
import * as React from "react";
interface SearchCriteriaProps {
placeholder: string;
doSearch: (criteria: string) => void;
}
interface SearchCriteriaState {
criteria: string;
}
class SearchCriteria extends React.Component<
SearchCriteriaProps,
SearchCriteriaState
> {
constructor() {
super();
this.state = {
criteria: ""
};
}
handleCriteriaChange = (e: React.FormEvent<HTMLInputElement>) => {
this.setState({ criteria: e.currentTarget.value });
};
handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
this.props.doSearch(this.state.criteria);
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className="input-group">
<input
type="text"
placeholder={this.props.placeholder}
value={this.state.criteria}
onChange={this.handleCriteriaChange}
className="form-control"
/>
<span className="input-group-btn">
<input type="submit" value="Submit" className="btn btn-secondary" />
</span>
</div>
</form>
);
}
}
export default SearchCriteria;
… and this component is referenced like the following in a calling component:
<SearchCriteria placeholder="Enter company name ..." doSearch={this.doSearch} />
At the moment, our submit button triggers the form’s submit which in tern calls handleSubmit()
which then calls this.props.doSearch
in our calling component to invoke the search (our calling component actually does the search).
Here’s what our component looks like at the moment:
We want to remove the submit button and just have the search invoke when the user stops typing.
So, let’s first remove the form and submit button from our render function:
render() {
return (
<div className="input-group">
<input
type="text"
placeholder={this.props.placeholder}
value={this.state.criteria}
onChange={this.handleCriteriaChange}
className="form-control"
/>
</div>
);
}
Now let’s just invoke the search in handleCriteriaChange
after we have set the criteria in the state:
handleCriteriaChange = (e: React.FormEvent<HTMLInputElement>) => {
this.setState({ criteria: e.currentTarget.value }, () => {
this.props.doSearch(this.state.criteria);
console.log(`doSearch(${this.state.criteria})`);
});
};
So, our component invokes the search on every keystroke that the user does:
Not quite what we want!
We need to “debounce” the search. That’s where the debounce function in the excellent lodash library comes in.
So, let’s bring lodash
and the TypeScript types into our project:
npm install --save lodash
npm install --save @types/lodash
We now need to import just the debounce function into our component:
import { debounce } from "lodash";
If we look at the docs, debounce
just creates another function that delays calling another function. So, let’s create our “debounce” function leaving the console.log()
so that we can check that doSearch
is only being called when the user has stopped typing:
raiseDoSearchWhenUserStoppedTyping = debounce(() => {
this.props.doSearch(this.state.criteria);
console.log(`doSearch(${this.state.criteria})`);
}, 300);
… and let’s call our new function from handleCriteriaChange
:
handleCriteriaChange = (e: React.FormEvent<HTMLInputElement>) => {
this.setState({ criteria: e.currentTarget.value }, () => {
this.raiseDoSearchWhenUserStoppedTyping();
});
};
… and let’s give this a try: … which is just what we want!
Here’s the full code for our debouncing search criteria component:
import * as React from "react";
import { debounce } from "lodash";
interface SearchCriteriaProps {
placeholder: string;
doSearch: (criteria: string) => void;
}
interface SearchCriteriaState {
criteria: string;
}
class SearchCriteria extends React.Component<
SearchCriteriaProps,
SearchCriteriaState
> {
raiseDoSearchWhenUserStoppedTyping = debounce(() => {
this.props.doSearch(this.state.criteria);
console.log(`doSearch(${this.state.criteria})`);
}, 300);
constructor() {
super();
this.state = {
criteria: ""
};
}
handleCriteriaChange = (e: React.FormEvent<HTMLInputElement>) => {
this.setState({ criteria: e.currentTarget.value }, () => {
this.raiseDoSearchWhenUserStoppedTyping();
});
};
render() {
return (
<div className="input-group">
<input
type="text"
placeholder={this.props.placeholder}
value={this.state.criteria}
onChange={this.handleCriteriaChange}
className="form-control"
/>
</div>
);
}
}
export default SearchCriteria;
If you to learn more about using TypeScript with React, you may find my course useful: