最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - filter vs map reactjs and jsx - Stack Overflow

programmeradmin2浏览0评论

I'm working on a react project to learn react.

In a component's render method, when I use .map to iterate over values and return an array of components, everything works as expected.

<ol className="books-grid">
        {              
          books && books.map((book, index) => {
            if (book.shelf === shelf) {
              return (
                <Book key={book && book.id ? book.id : index} changeShelf={this.props.changeShelf} book={book} />
              );
            }
          })}
      </ol>

But when I use filter:

<ol className="books-grid">
            {              
              books && books.filter((book, index) => {
                if (book.shelf === shelf) {
                  return (
                    <Book key={book && book.id ? book.id : index} changeShelf={this.props.changeShelf} book={book} />
                  );
                }
              })}
          </ol>

I get the error (which I've researched)

Uncaught (in promise) Error: Objects are not valid as a React child

I don't understand why filter is throwing this error vs map? Is there something unique to react and .map? Both return an array.

I'm working on a react project to learn react.

In a component's render method, when I use .map to iterate over values and return an array of components, everything works as expected.

<ol className="books-grid">
        {              
          books && books.map((book, index) => {
            if (book.shelf === shelf) {
              return (
                <Book key={book && book.id ? book.id : index} changeShelf={this.props.changeShelf} book={book} />
              );
            }
          })}
      </ol>

But when I use filter:

<ol className="books-grid">
            {              
              books && books.filter((book, index) => {
                if (book.shelf === shelf) {
                  return (
                    <Book key={book && book.id ? book.id : index} changeShelf={this.props.changeShelf} book={book} />
                  );
                }
              })}
          </ol>

I get the error (which I've researched)

Uncaught (in promise) Error: Objects are not valid as a React child

I don't understand why filter is throwing this error vs map? Is there something unique to react and .map? Both return an array.

Share Improve this question asked Jan 6, 2018 at 1:02 HelloWorldHelloWorld 11.2k10 gold badges33 silver badges55 bronze badges 1
  • 1 Have you tried dumping the book object in both cases as received in the filter and map callback arrow functions as argument? I am most positive you will see some differences. – marekful Commented Jan 6, 2018 at 1:20
Add a comment  | 

5 Answers 5

Reset to default 29

Array.filter does not allow you to transform the data into components. That is the job of Array.map.

You should instead filter first, then chain the map call afterward:

{              
  books && books
    .filter(book => book.shelf === shelf)
    .map((book, index) => {
      return (
        <Book
           key={book && book.id ? book.id : index}
           changeShelf={this.props.changeShelf}
           book={book} />
      );
    })
}

If you want to avoid a second pass over your list of books, you can return null as well, though this is "less good" because you're forcing React to render null when it doesn't need to do any work at all:

{              
  books && books
    .map((book, index) => {
      if (book.shelf !== shelf) {
        return null;
      }
      return (
        <Book
           key={book && book.id ? book.id : index}
           changeShelf={this.props.changeShelf}
           book={book} />
      );
    })
}

There is nothing unique to React and map() or filter().

In the first example when using map() you are returning an array of React components which are rendered in the DOM. You are transforming (mapping) each plain JavaScript object in the array into a React component. As a matter of fact, you are also going to return some undefined elements in the resulting array, if the condition book.shelf === shelf is falsy. Your array may look like [<Book />, <Book />, undefined, <Book />, undefined]. That's not such a big deal, since React won't render falsy values (null or undefined elements will just be skipped).

The second example won't return the same result (an array of React components), but an array of plain JavaScript objects (of type book). This is because no matter what are you returning from the filter function, it's going to be cast to a Boolean value - true or false and that value is going to decide if the current element is going to be filtered or not. The result of your .filter() function is going to be something like this (imagine shelf === 'Science'):

Original array: [{ shelf: "Science" }, { shelf: "Thrillers" }, { shelf: "Informatics" }]
Filtered array: [{ shelf: "Science" }]

As you can see, the items in the array won't be React components (<Book />) and React won't be able to render them in the DOM, thus the error it throws.

If you only want to use one pass over the array you can use reduce:

books && books
.reduce(
  (all,book, index) => {
    if (book.shelf !== shelf) {
      return all;
    }
    return all.concat(
      <Book
        key={book && book.id ? book.id : index}
        changeShelf={this.props.changeShelf}
        book={book} />
    );
  }
  ,[]
)

However; I think using filter and map makes for code that's easier to read.

The answer to me seems good but I needed to use includes() in order to work, also maybe a good idea to use toLowerCase():

{              
  books && books
    .filter(book => book.shelf.toLowerCase().includes(shelf.toLowerCase()))
    .map((book, index) => {
      return (
        <Book
           key={book && book.id ? book.id : index}
           changeShelf={this.props.changeShelf}
           book={book} />
      );
    })
}

I also facing the same error. then, I also wrap my map method on filter method which helps me to solve the error and accept it as react valid child.

<ul className="menu">
            {navigationLinks?.filter((eachNavigation) => {
              if (eachNavigation.select.length < 1) {
                return eachNavigation;
              }
            }).map((eachNavigation, index) => {
              return (
                <li key={index} className="menu__list menu__list--noSelect">
                  <a href={eachNavigation.link}>{eachNavigation.title}</a>
                </li>
              )
            })
            }
          </ul>

<ul className="menu">
                {navigationLinks?.filter((eachNavigation) => {
                  if (eachNavigation.select.length < 1) {
                    return eachNavigation;
                  }
                }).map((eachNavigation, index) => {
                  return (
                    <li key={index} className="menu__list menu__list--noSelect">
                      <a href={eachNavigation.link}>{eachNavigation.title}</a>
                    </li>
                  )
                })
                }
              </ul>

发布评论

评论列表(0)

  1. 暂无评论