简体   繁体   English

过滤器 vs 映射 reactjs 和 jsx

[英]filter vs map reactjs and jsx

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.在组件的渲染方法中,当我使用.map迭代值并返回组件数组时,一切都按预期工作。

<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 :但是当我使用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 ?我不明白为什么filter会抛出这个错误 vs map Is there something unique to react and .map ? react 和.map有什么独特之处吗? Both return an array.两者都返回一个数组。

Array.filter does not allow you to transform the data into components. Array.filter不允许您将数据转换为组件。 That is the job of Array.map .这就是Array.map的工作。

You should instead filter first, then chain the map call afterward:您应该先过滤,然后链接 map 调用:

{              
  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列表,你也可以返回null ,尽管这“不太好”,因为当 React 根本不需要做任何工作时,你会强制它呈现null

{              
  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() . React 和map()filter()没有什么独特之处。

In the first example when using map() you are returning an array of React components which are rendered in the DOM.在使用map()的第一个示例中,您将返回一个在 DOM 中呈现的 React 组件数组。 You are transforming (mapping) each plain JavaScript object in the array into a React component.您正在将数组中的每个普通 JavaScript 对象转换(映射)为 React 组件。 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.事实上,如果条件book.shelf === shelf为假,您还将在结果数组中返回一些undefined元素。 Your array may look like [<Book />, <Book />, undefined, <Book />, undefined] .您的数组可能看起来像[<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).这没什么大不了的,因为 React 不会渲染虚假值(只会跳过nullundefined元素)。

The second example won't return the same result (an array of React components), but an array of plain JavaScript objects (of type book).第二个示例不会返回相同的结果(一组 React 组件),而是一组纯 JavaScript 对象(类型为 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.这是因为无论您从过滤器函数返回什么,它都会被转换为Boolean值 - truefalse并且该值将决定当前元素是否将被过滤。 The result of your .filter() function is going to be something like this (imagine shelf === 'Science' ):您的.filter()函数的结果将是这样的(想象一下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.如您所见,数组中的项目不会是 React 组件( <Book /> )并且 React 将无法在 DOM 中呈现它们,因此会引发错误。

If you only want to use one pass over the array you can use reduce:如果您只想对数组使用一次传递,则可以使用 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.我认为使用filtermap可以使代码更易于阅读。

The answer to me seems good but I needed to use includes() in order to work, also maybe a good idea to use toLowerCase() :我的答案似乎不错,但我需要使用includes()才能工作,使用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.然后,我还将我的map方法包装在filter方法上,这有助于我解决错误并将其作为反应有效子项接受。

<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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM