【问题标题】:filter vs map reactjs and jsx过滤器与映射 reactjs 和 jsx
【发布时间】:2018-01-06 01:02:09
【问题描述】:

我正在做一个 React 项目来学习 React。

在组件的渲染方法中,当我使用.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>

但是当我使用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>

我得到了错误(我已经研究过)

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

我不明白为什么 filtermap 相比会抛出此错误?有什么独特的反应和.map?两者都返回一个数组。

【问题讨论】:

  • 您是否尝试过在过滤器和映射回调箭头函数中接收到的这两种情况下的图书对象作为参数?我很肯定你会看到一些差异。

标签: javascript reactjs


【解决方案1】:

Array.filter 不允许您将数据转换为组件。那是Array.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} />
      );
    })
}

如果你想避免第二次遍历你的 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} />
      );
    })
}

【讨论】:

  • 如果你想要一张通行证,你应该使用reduce
  • 这个答案很好但是对我来说我需要使用includes(),我会在下面发布我的答案版本
【解决方案2】:

React 和 map()filter() 没有什么独特之处。

在第一个示例中,当使用 map() 时,您将返回一个在 DOM 中呈现的 React 组件数组。您正在将数组中的每个普通 JavaScript 对象转换(映射)为一个 React 组件。事实上,如果条件book.shelf === shelf 是假的,您还将在结果数组中返回一些undefined 元素。你的数组可能看起来像[&lt;Book /&gt;, &lt;Book /&gt;, undefined, &lt;Book /&gt;, undefined]。这没什么大不了的,因为 React 不会呈现虚假值(nullundefined 元素将被跳过)。

第二个示例不会返回相同的结果(一个 React 组件数组),而是一个纯 JavaScript 对象数组(类型为 book)。这是因为无论您从过滤器函数返回什么,它都将被转换为 Boolean 值 - truefalse 并且该值将决定当前元素是否要被过滤或不是。 .filter() 函数的结果将是这样的(想象一下 shelf === 'Science'):

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

如您所见,数组中的项目不会是 React 组件 (&lt;Book /&gt;),React 将无法在 DOM 中呈现它们,因此会引发错误。

【讨论】:

    【解决方案3】:

    如果你只想在数组上使用一次,你可以使用 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} />
        );
      }
      ,[]
    )
    

    但是;我认为使用filtermap 可以使代码更易于阅读。

    【讨论】:

      【解决方案4】:

      对我来说答案似乎不错,但我需要使用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} />
            );
          })
      }
      

      【讨论】:

        【解决方案5】:

        我也面临同样的错误。然后,我还将我的 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>

        【讨论】:

        • 这并不能真正回答问题。如果您有其他问题,可以点击 进行提问。要在此问题有新答案时收到通知,您可以follow this question。一旦你有足够的reputation,你也可以add a bounty 来引起对这个问题的更多关注。 - From Review
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-01
        • 2019-05-19
        • 1970-01-01
        • 1970-01-01
        • 2012-04-24
        相关资源
        最近更新 更多