Ron Allen Smith
Ron Allen Smith

Reputation: 603

Filtering A List With React

Hmm, I don't see my omission, but I get a blank page with a console error saying:

Users.js:9 Uncaught TypeError: Cannot read property 'filter' of undefined
    at Users.render (Users.js:9)

Apparently I'm using 'filter()' improperly. I looked around but didn't find anything 'React' related. Can Anyone help? Here are the files:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>React App</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import Users from './Users';

ReactDOM.render(
  <Users list={[
    { name: 'Tyler', friend: true },
    { name: 'Ryan', friend: true },
    { name: 'Michael', friend: false },
    { name: 'Mikenzie', friend: false },
    { name: 'Jessica', friend: true },
    { name: 'Dan', friend: false }
    ]}
  />,
  document.getElementById('root')
);

Users.js

import React from 'react';

class Users extends React.Component {
  render() {
    return (
      <div>
        <h1>Friends:</h1>
        <ul>
          {this.props.list.friend.filter(function (friend) {
            return <li>{friend[0] === 'true'}</li>
        })}
        </ul>

        <hr />

        <h1>Non Friends:</h1>
        <ul>
          {this.props.list.friend.filter(function (nonFriend) {
            return <li>{nonFriend[0] === 'false'}</li>
          })}
        </ul>
      </div>
    );
  }
}

export default Users;

Upvotes: 17

Views: 122559

Answers (5)

user15373964
user15373964

Reputation: 11

  {items.filter((product) => {
                    if (searchterm === "") {
                        return product
                    }
                    else if (product.title.toLowerCase().includes(searchterm.toLocaleLowerCase())) {
                        return product
                    }

                })

Upvotes: -1

Ron Allen Smith
Ron Allen Smith

Reputation: 603

Okay, looks like "Users.js" should be:

import React from 'react';

class Users extends React.Component {
  render() {
    let friends = this.props.list.filter( function (user) {
      return user.friend === true
    });

    let nonFriends = this.props.list.filter( function (user) {
      return user.friend !== true
    });

    return (
      <div>
        <h1>Friends:</h1>
        <ul>
          {friends.map(function (user) {
            return <li key={user.name}>{user.name}</li>
          })}
        </ul>
        <h1>Non Friends:</h1>
        <ul>
          {nonFriends.map(function (user) {
            return <li key={user.name}>{user.name}</li>
          })}
        </ul>
      </div>
    );
  }
}

export default Users;

Or even this:

import React from 'react';

class Users extends React.Component {
  render() {
    return (
      <div>
        <h1>Friends:</h1>
        <ul>
          {this.props.list.filter(function (user) { // filter first for friends
            return user.friend === true // returns a new array
          }).map(function (user) {  // map the new array to list items
            return <li key={user.name}>{user.name}</li> // don't forget unique key for each item
          })}
        </ul>

        <hr />

        <h1>Non Friends:</h1>
        <ul>
          {this.props.list.filter(function (user) { // filter first for non-friends
            return user.friend !== true // returns a new array
          }).map(function (user) {  //map the new array to list items
            return <li key={user.name}>{user.name}</li> // don't forget unique key for each item
          })}
        </ul>
      </div>
    );
  }
}

export default Users;

Upvotes: 11

oftenfrequent
oftenfrequent

Reputation: 64

I would do something like this instead which is a little more straightforward

{this.props.list.map(function (person, i) {
  {return person.friend
    ?(<li key={i}>{person.name}</li>)
    : null
  }
})}
  1. You are iterating over the list itself, not an item in the list which is why this.props.list.friend.filter didn't work.
  2. I would use map because you are not actually filtering the lists in this case. If you wanted to you could filter the list beforehand into friends and non friends and map over those items which would actually be more straightforward for another engineer to see.
  3. React wants keys in the markup for the iterated items created. That is how React creates the relationships between components in the state tree.

Upvotes: 3

Vinay
Vinay

Reputation: 6342

You are calling .friend on the list itself when that's a property of each object in your array. You are also using .filter, but I don't think you're using it correctly here. .filter will return an array with certain elements where the function passed in returns a truthy value. Here's how you could do it with .filter:

var nonFriends = this.props.list.filter(function (user) {
  return !user.friend;
});

var friends = this.props.list.filter(function (user) {
  return user.friend;
});

return (
  <div>
    <h1>Friends:</h1>
    <ul>{ friends }</ul>
    <h1>Non Friends:</h1>
    <ul>{ nonFriends }</ul>
  </div>
);

You could also do a .forEach for 1 pass through the array if the array is large:

var nonFriends = [], friends = [];

this.props.list.forEach(function (user) {
  if (user.friend) {
    friends.push(user);
  } else {
    nonFriends.push(user);
  }
});

// now render friends and nonFriends

Upvotes: 4

Ariel Jr
Ariel Jr

Reputation: 61

I think that you are trying to filter the atribute, and not the list. Try to change this:

this.props.list.friend.filter

to this:

this.props.list.filter

Upvotes: 2

Related Questions