Reputation: 411
I'm new to react, and I'm working on a small project that uses a search bar to find data that I've gotten from my database.
The code for this component is below:
import React, { Component } from 'react';
class BodyData extends Component {
state = {
query: '',
data: [],
}
handleInputChange = () => {
this.setState({
query: this.search.value
})
this.filterArray();
}
getData = () => {
fetch(`http://localhost:4000/restaurants`)
.then(response => response.json())
.then(responseData => {
// console.log(responseData)
this.setState({
data:responseData
})
})
}
filterArray = () => {
var searchString = this.state.query;
var responseData = this.state.data
if(searchString.length > 0){
// console.log(responseData[i].name);
responseData = responseData.filter(l => {
console.log( l.name.toLowerCase().match(searchString));
})
}
}
componentWillMount() {
this.getData();
}
render() {
return (
<div className="searchForm">
<form>
<input type="text" id="filter" placeholder="Search for..." ref={input => this.search = input} onChange={this.handleInputChange}/>
</form>
<div>
{
this.state.data.map((i) =>
<p>{i.name}</p>
)
}
</div>
</div>
)
}
}
export default BodyData;
So basically, I want to update the state as I type in the query text, and have the restaurant names I've mapped be reduced till a match is found.
From what I understood, this.state.data
will be filtered as I type in my query in the search bar. However when I map out this.state.data
, I get the whole list of restaurants instead of what I want to see.
Ive been through a bunch of tutes, and I'm not exactly sure how to go about doing that.
Can anyone help me with this please? Any other comments on the code are also welcome. I'm here to learn :)
Thank you!
Upvotes: 9
Views: 68741
Reputation: 293
Here is the code that will work for you
import React, { Component } from 'react';
class BodyData extends Component {
state = {
query: '',
data: [],
searchString:[]
}
handleInputChange = (event) => {
this.setState({
query: event.target.value
},()=>{
this.filterArray();
})
}
getData = () => {
fetch(`http://localhost:4000/restaurants`)
.then(response => response.json())
.then(responseData => {
// console.log(responseData)
this.setState({
data:responseData,
searchString:responseData
})
})
}
filterArray = () => {
let searchString = this.state.query;
let responseData = this.state.data;
if(searchString.length > 0){
// console.log(responseData[i].name);
responseData = responseData.filter(searchString);
this.setState({
responseData
})
}
}
componentWillMount() {
this.getData();
}
render() {
return (
<div className="searchForm">
<form>
<input type="text" id="filter" placeholder="Search for..." onChange={this.handleInputChange}/>
</form>
<div>
{
this.state.responseData.map((i) =>
<p>{i.name}</p>
)
}
</div>
</div>
)
}
}
export default BodyData;
There are few changes which is needed.
Enjoy Coding!!
Upvotes: 5
Reputation: 112787
You could keep an additional piece of state called e.g. filteredData
that contains all elements in data
that include your query
in the name, and then render that.
Example
class BodyData extends React.Component {
state = {
query: "",
data: [],
filteredData: []
};
handleInputChange = event => {
const query = event.target.value;
this.setState(prevState => {
const filteredData = prevState.data.filter(element => {
return element.name.toLowerCase().includes(query.toLowerCase());
});
return {
query,
filteredData
};
});
};
getData = () => {
fetch(`http://localhost:4000/restaurants`)
.then(response => response.json())
.then(data => {
const { query } = this.state;
const filteredData = data.filter(element => {
return element.name.toLowerCase().includes(query.toLowerCase());
});
this.setState({
data,
filteredData
});
});
};
componentWillMount() {
this.getData();
}
render() {
return (
<div className="searchForm">
<form>
<input
placeholder="Search for..."
value={this.state.query}
onChange={this.handleInputChange}
/>
</form>
<div>{this.state.filteredData.map(i => <p>{i.name}</p>)}</div>
</div>
);
}
}
Upvotes: 7
Reputation: 4537
Few pointers I'll like to show-
setState({})
function is asynchronous, you'll have to either use functional setState
and call filteredArray
method as a callback. Or, call filteredArray
at render
, which is where your values will be updated and be reflected.filterArray
method is not returning / setting the filtered list of data. So what you type, even though it is getting filtered, it is not getting set / returned anywhere.Upvotes: 0
Reputation: 1101
setState method is asynchronous and it has second parameter - callback that is called when the state is applied.
You need to change handleInputChange
methods.
handleInputChange = () => {
this.setState({
query: this.search.value
}, this.filterArray)
}
Upvotes: 0