Danny Dyer Danny Dyer - 1 month ago 7
React JSX Question

React filter not filtering through objects

I'm new to react and have a problem with rendering out some filtered data to a component.

I have data that gets imported into state of a parent container like so:

getInitialState () {
return {
samples:allSamples,
searchInputVal:""
}
},


Here is the data that gets loaded into the samples initial state:

export default [
{
id:"1",
sampleName:'Deep House Base',
sampleFamily:'Deep House Pack',
parentCategory:"bass",
subCategory:"house bass",
uploader:"Ben",
soundSource:"../../samplesWav/bd_909dwsd.wav",
tags:[
"house","ghouse","tech-house","rad"
]
},
{
id:"2",
sampleName:'Deep House Base',
sampleFamily:'G House Pack',
parentCategory:"bass",
subCategory:"house bass",
uploader:"Ben",
soundSource:"../../samplesWav/bd_chicago.wav",
tags:[
"house","ghouse","tech-house","rad"
]
}
]


I have created a header component that is child of with an input to server as a filter function like so:

<input placeholder="Search Samples Here..." onChange={this.props.updateSearch} value={this.props.searchInputVal} type="text"></input>


onChange it performs the updateSearch function in its parent. This is what that function looks like:

updateSearch(event){
this.setState({
searchInputVal:event.target.value.substr(0,20)
})
},


Currently when I type letters in the input the state is updating with the value so that part is working fine. It's the part where I render out my objects that isn't filtering. Here is the component i'm trying to filter:

class SamplesInnerLrg extends Component {
render() {
let filteredSamples = this.props.loadAllInitSamples.filter(
(sample) => {
return sample.sampleFamily.indexOf(
this.props.searchInputVal
)
}
)
return <div className="samples-container-inner-styling">
{
console.log(filteredSamples),
filteredSamples.map((sample) => {
return (
<div key={sample.id} className="sample-comp-lge">
<div className="sample-comp-lge-head-wrap">
<div className="sample-comp-lge-audio" id={sample.id} ref={sample.id} onClick={this.playSampleAction.bind(undefined,sample,sample.id)}>
<audio preload="auto" className="audioTag">
<source src={sample.soundSource} type="audio/wav" />
</audio>
</div>
<div className="sample-comp-lge-header">
<span className="sample-comp-lge-Name"><h1>{sample.sampleName}</h1></span>
<span className="sample-comp-lge-id"><h2><a href="#">{sample.sampleFamily}</a></h2></span>
<div className="sample-comp-lge-owner-cont">
<div className="sample-comp-lge-owner-inner">
<a href="">{sample.uploader}</a>
</div>
</div>
</div>
</div>
<div className="sample-comp-lge-bottom-wrap">
<div className="sample-comp-lge-tags-cont">
<div className="sample-comp-lge-tag">
<ul className="sample-tags-list">
{
sample.tags.map((tag) => {
return (

<li key={tag}><a href="#">#{tag}</a></li>
)
})

}
</ul>
</div>
</div>
</div>

</div>
)
})
}
</div>
}
}


There are two problems here with my render of this component. First of all when I load the page there are no objects being rendered to the DOM but when I starting typing in the input box they suddenly appear. Second, it doesn't matter what I type they will all appear no matter what (I have more than 2 but for the sake of StackOverflow I only included 2). Where have I gone wrong?

Answer

This line:

let filteredSamples = this.props.loadAllInitSamples.filter(
        (sample) => {
            return sample.sampleFamily.indexOf(
                this.props.searchInputVal
            )
        }
)

...is problematic. indexOf returns an index or -1 if nothing is found. .filter(...) expects the function to return a boolean value. You'll want to add a >= 0 to your index result to convert it to a boolean (assuming you want "is present" to be true):

const filteredSamples = this.props.loadAllInitSamples.filter(sample => {
  return sample.sampleFamily.indexOf(this.props.searchInputVal) >= 0;
});
Comments