React live search
September 20, 2021
Content |
---|
Multiple cards components |
Getting input value |
Filtering out users |
Starting point
Let's say I have a list of cards components each holding data about a user, and I want to add a search feature to it. Maybe something as shown here below:

Goal: live search update
I need a search box that takes the typed input and filters out the cards based on what a person types in.
I've initialized a cards's array. Cards's data is fetched during component mounting phase with the entire cards' list mapped out by CardList component.
app.js
------
this.state = {
cards: []
}
componentDidMount() {
// fetch cards and
// updates cards array
}
...
render() {
<div className="app">
<CardList users={this.state.cards}>
</div>
}
In order to live update my cards with the input generated from the search box, I need to store in whatever a person enters into the input box. So for that I create a new piece of state: searchField.
I also need to wire up an onChange event listener to react to changes, as new values are being entered.
Getting the input value
this.state = {
cards: []
searchField: '',
}
...
render() {
return (
<div className="app">
<input
type="search"
placeholder="enter name"
onChange={(e) => this.setState({
searchField: e.target.value
})}
/>
<CardList users={this.state.users}>
</div>
)}
Normally with React, if you console.log what's being entered into the input box, you'll noticed that the state although it gets updated, it's always a letter behind, but it's not a bug. It's because of React's state being asynchronous.
<input
type="search"
placeholder="enter name"
onChange={(e) =>
console.log(e.target.value)
)}
/>
To log the actual value being entered into the search field, you need to pass the console.log var
as the second argument to the setState function; which returns a callback with the updated state, as shown below.
<input
type="search"
placeholder="enter name"
onChange={(e) => this.setState({
searchField: e.target.value
}, () => {
console.log(this.state)
})
/>
Filtering out users
Let's say the search field takes in peoples names, that are then run against our list of cards, in order to filter out those that don't match. So far it seems nothing more than a map/filter combination at most. What makes it a live search feature is the placement of the filtering function, within the render section of the component because it'll ensured that it gets updated everytime there's a state change.
Also we'd want to avoid modifying the actual cards array state as we do this.
render() {
const { users, searchField } = this.state;
const filteredUsers = users.filter(usr =>
usr.name.toLowerCase().includes(
searchField.toLowerCase()
))
return (
<div className="app">
<input
type="search"
placeholder="enter name"
onChange={(e) => this.setState({
searchField: e.target.value
})}
/>
//no longer this.state.users
<CardList users={filteredUsers}>
</div>
)}
By using filteredUsers
function, we're making sure not to modify the original card's array.
As a user types in, it triggers setState
; which in turn sets the state value of searchField
; which in turn causes the app to re-render, and recall the render method; which calls filteredUsers
function returning a new array of re-filtered users, that are passed for re-rendering to CardList
component; which in turn updates the current list of users shown in the page.