Creating an Autocomplete Search Bar in React with Redux
Last month I created a yelp-style application using React/Redux with a Rails API backend. I wanted to continue refining my React knowledge and decided that adding an autocomplete search bar would be a really helpful element, since searching for a type of business is the first thing someone does to interact with this application.
I pulled some of the wisdom from this Dev.to post as well as this one and adapted their code to fit my purposes.
Since my application uses Redux, I didn’t need to include a fetch
or axios
call in my search component. I simply had to access all of the possible search results by connecting my component to the Redux store and mapping my global state to the component’s props.
I’ll leave the Redux functionality for another post, for now, let’s focus on the auto-complete search bar. To set up my search bar, I created a component with local state that was also connected to my Redux store as well as a functional component that just presents the auto-completed results as a <ul>
beneath the search bar.
I called my search bar component HomeSearch
and set it up with a very simple local state:
class HomeSearch extends Component {
state = {
search: '',
results: [],
}
I connected it to my Redux store with connect
which I imported from 'react-redux'
and mapped my global state to this component’s props as categories.
const mapStateToProps = (state) => {
return {
categories: state.categoriesReducer.categories
}
}export default connect(mapStateToProps)(HomeSearch);
Here’s how I set up my search bar. I used Semantics UI to style my application, which is why my Input
element looks like it’s its own React component. Implementing a regular <input/>
tag will work just fine here as well.
<Input
name="category"
onChange={this.handleChange}
value={this.state.search}
placeholder="Search for a type of business..."
/>
My handleChange()
function sets my state to reflect the user’s input as they type and, if the user’s input is longer than one letter long, calls on getResults()
which filters through all the categories from the Redux store (now in HomeSearch
's props) to match the first letter of the input with the first letter of a category.
handleChange = (e) => {
this.setState({
...this.state,
search: e.target.value
}, () => {
if (this.state.search && this.state.search.length >= 1) {
this.getResults()
}
})
}getResults = () => {
let m = this.state.search.substring(0,1)
this.setState({
...this.state,
results: this.props.categories.filter(c => c.name.startsWith(m))
})
}
getResults()
will populate the state’s results key with an array of category objects, whose names start with the letter that matches the first letter of the user’s input. I chose to match only the first letter here because the database I was working with was on the smaller side.
Once my state is populated with a few results, I send those results, as props to my functional component, which I called Suggestions
. My Suggestions
component also receives a method handleQueryResultClick()
.
Here’s what my Suggestions
component looks like:
import React from 'react'
import uuid from 'react-uuid'const Suggestions = ({results, handleQueryResultClick}) => { const queryOptions = results.map(r => (
<li className='search-results' key={uuid()} id={r.name} onClick={handleQueryResultClick}>{r.name}</li>
)) return (
<ul>{queryOptions}</ul>
)
}export default Suggestions;
I map over the results array, creating an <li>
for each result. Each <li>
has a key, an id (so that the category can be identified by it’s name) and the handleQueryResultClick
method passed down from my HomeSearch
component.
Here’s what this looks like in the application.
When a user clicks on one of the displayed options, handleQueryResultClick
kicks in.
handleQueryResultClick = (e) => {
const searchResultName = e.target.id;
this.setState({
search: searchResultName,
results: []
})
}
This arrow function grab’s the category’s name from e.target.id
then sets the local state to reflect that name in the search bar. It also clears the results array, thus eliminating our Suggestions
component.
Creating this functionality was pretty simple and definitely enhances the user experience when interacting with this app.
Thanks for reading!