Sireini
Sireini

Reputation: 4262

ReactJs trying to create a filter list

I am trying to create an filter list which filter the list on typed input. But don't know why the if statement is not working.

Here is the function I wrote: `

filterList (event) {
    var updatedList = this.props.array; 
    var filterText = this.state.text;
    updatedList = updatedList.filter(function(item){
      console.log(filterText);
      if(item.name === filterText){
        console.log('check', item.name);
      }
    });

Can someone help me out on this here is a link to my codepen: LINK

Upvotes: 1

Views: 3771

Answers (2)

Kryten
Kryten

Reputation: 15760

First, when I run your codepen example, I'm not seeing any errors indicating that this.state.text is undefined. It's not filtering anything, but it is displaying the value of this.state.text. So the issue is not quite what your question suggests it is...

So how to we get this thing filtering? Basically, the idea with ReactJS components is that everything related to the current state of your component should be in this.state, and any decisions about what to display based on that state should be in the render method. And keep in mind that any time you change the state using the setState method, it's going to trigger a re-rendering of your component.

With that in mind, I'd set things up like this:

  1. your component receives a list of photos via the array prop (I'd probably call it something else, since it's not very descriptive and it's awfully close to a reserved word in Javascript)

  2. the state for the component has one value: text (again, not very descriptive)

  3. the component has a handleChange handler for the input element. I would connect this to the onChange handler for the input element - don't worry, it will be called every time the value in the input element changes. This should be the only event handler on the input element and all it should do is call this.setState({ text: event.target.value });

  4. do the list filtering in the render method. The key here is that you don't need to keep a filtered list of your photos - all you're doing with it is rendering it, so do it only when you need to (or rather, when React thinks you need to and calls the render method). So your render method will look something like this:

    render() {
        var myFilteredList = this.props.array.filter(function(item){
            console.log(filterText);
            if(item.name === filterText){
                console.log('check', item.name);
                return true;
            }
    
            return false;
        });
    
        var arrayComponents = myFilteredList.map(function(photo) {
            return <li className="photo photo-name">{photo.name} <img className="photo" src={photo.link}/></li>;
        });
    
        return (
        <div>
            <h1>Hello, {this.props.name}</h1>
            <p>{this.state.text}</p>
            <input type="text"  onKeyUp={this.handleChange} />
            <ul>
                {arrayComponents}
            </ul>
        </div>
        );
    }
    

That's it. This has a couple of advantages:

  1. it keeps it simple - don't maintain any state for the component outside of this.state and if you only need it for rendering, don't maintain it at all.

  2. it keeps your code cleaner - the way I've approached it, your component has only two methods: handleChange and render

  3. it (should be) more performant - React is pretty good at deciding when to render based on state changes, and it tends to be better when components have minimal state. (I say "should be" simply because I haven't tested it out at all).

Upvotes: 1

agmcleod
agmcleod

Reputation: 13621

Your filter needs to update the array in the component state to force a re-render. You don't update props to force a re-render, props are more for initial data, or consistent data, which can be updated from the top level.

Change the handle function to pass the text to the filterList function, and return the result

handleChange(event) {
  var array = this.filterList(event.target.value);
  this.setState({ text: event.target.value, array: array });
},

filterList (filterText) {
  var updatedList = this.props.array;
  return updatedList.filter(function(item){
    return item.name === filterText;
  });
}

Update getInitialState to use the props:

getInitialState() {
  return { text:'', array: this.props.array};
}

Then use the state instead of props in your render:

var arrayComponents = this.state.array.map(function(photo) {
     return <li className="photo photo-name">{photo.name} <img className="photo" src={photo.link}/></li>;
})

Upvotes: 1

Related Questions