过滤器 vs 映射 reactjs 和 jsx

IT技术 javascript reactjs
2021-04-30 08:01:46

我正在做一个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

我不明白为什么filter会抛出这个错误 vs map有什么独特的react.map吗?两者都返回一个数组。

4个回答

Array.filter不允许您将数据转换为组件。这就是 的工作Array.map

您应该先过滤,然后链接 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,尽管这“不太好”,因为null当它根本不需要做任何工作时,你会强迫 React 渲染

{              
  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} />
      );
    })
}

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

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

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

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

如您所见,数组中的项目不会是 React 组件 ( <Book />) 并且 React 将无法在 DOM 中呈现它们,因此会抛出错误。

如果您只想对数组使用一次传递,则可以使用 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使代码这更易于阅读。

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