【问题标题】:How to create a new array based on the selected value from an existiing array in reactjsreactjs - 如何根据从现有数组中的选定值创建新数组
【发布时间】:2017-10-12 01:49:27
【问题描述】:

我有一个来自 API 的书籍数组。当用户从下拉列表中选择一个值时,我想过滤书籍数组并将所选书籍放在一个新数组中。所以,我的书将有一个下拉列表将有 3 个值:1)当前正在阅读 2)想要阅读和 3)阅读。现在我在我的反应状态下创建了 3 个数组。因此,当用户从下拉列表中选择一个值时,它会将书移动到为其定义的数组。为此,我有一个 handleChange() 函数,它将获取数组的值,但我无法弄清楚如何删除从书籍数组中选择的书籍并将其移动到选定的选项数组。那么如何根据条件过滤出书籍数组并将其放入新数组中。

更新书目代码:

import React, { Component } from 'react';

class BooksList extends Component {
    constructor(props) {
      super(props);
      this.state={
        showSearchPage: false,
        books: this.props.books.map(book => Object.assign({}, book, {status:"none"}))
      };
        this.handleChange = this.handleChange.bind(this);
      }



  handleChange=(index,event) => {
    let books = this.state.books;
    books[index].status = event.target.value;
    this.setState({ books });
  }

  componentWillReceiveProps(nextProps) {
  if (this.props.books !== nextProps.books) {
    this.setState({ books: nextProps.books.map(book => Object.assign({}, book, { status: "none" })) });
  }
}

  render() {
    return(
        <div className="app">
          {this.state.showSearchPage ? (


            <div className="search-books">
              <div className="search-books-bar">
                <a className="close-search" onClick={() => this.setState({ showSearchPage: false })}>Close</a>
                <div className="search-books-input-wrapper">
                  {
                  <input type="text" placeholder="Search by title or author"/>

                </div>
              </div>
              <div className="search-books-results">
                <ol className="book-search">

                {<div className="book-search">
                  {this.state.books.map( (book,index) =>

                    <div key={index} className="book">
                      <div className="book-top">
                        <div className="book-cover" style={{ width: 128, height: 193,margin:10, backgroundImage: `url(${book.imageLinks.smallThumbnail})` }}></div>
                        <div className="book-shelf-changer">
                          <select
                            value={book.status}
                            onChange={(event) => this.handleChange(book.index,event)}>
                            <option value="none" disabled>&nbsp; &nbsp; Move to...</option>
                            <option value="currentlyReading">&#x2714; Currently Reading</option>
                            <option value="wantToRead">&nbsp; &nbsp; Want to Read</option>
                            <option selected="selected" value="read">&nbsp; &nbsp; Read</option>
                            <option value="none">&nbsp; &nbsp; None</option>
                          </select>
                        </div>
                      </div>
                      <div className="book-title">{book.title}</div>
                      <div className="book-authors">{book.authors}</div>
                      <p>{book.status}</p>
                    </div>
              )}
              </div>
                }

App.js:

import React from 'react'
// import * as BooksAPI from './BooksAPI'
import './App.css'
import * as BooksAPI from './BooksAPI'
import BooksList from './BooksList'

class BooksApp extends React.Component {
  state = {
    showSearchPage: false,
    selectValue: 'None',
    books: []
  }

  componentDidMount() {
    BooksAPI.getAll().then((books) => {
      this.setState({ books })
      console.log(books[0])
    })

  }

  render() {
    return (
      <BooksList books={this.state.books}/>
    )
  }
}

export default BooksApp

那么我该如何编写handleChange方法来获取选中的数组呢?

编辑 1:更新了代码。

所以,下面是我在控制台中遇到的错误:

Uncaught TypeError: Cannot set property 'status' of undefined
    at BooksList._this.handleChange (BooksList.js:17)
    at Object.executeOnChange (LinkedValueUtils.js:130)
    at ReactDOMComponent._handleChange (ReactDOMSelect.js:188)
    at HTMLUnknownElement.boundFunc (ReactErrorUtils.js:63)
    at Object.ReactErrorUtils.invokeGuardedCallback (ReactErrorUtils.js:69)
    at executeDispatch (EventPluginUtils.js:83)
    at Object.executeDispatchesInOrder (EventPluginUtils.js:106)
    at executeDispatchesAndRelease (EventPluginHub.js:41)
    at executeDispatchesAndReleaseTopLevel (EventPluginHub.js:52)
    at Array.forEach (<anonymous>)

编辑 2:添加了包含 ComponentDidMount 生命周期方法的 App.js 文件:

【问题讨论】:

  • 查看 3 个下拉列表值是否是用户特定的,这意味着用户应该已经告诉您他/她想要阅读 xyz 书或已经阅读或正在阅读它。现在您应该已将这些详细信息(例如书的 ID)存储在某处。您可以使用这些详细信息从主数组中获取图书的其他详细信息。

标签: javascript reactjs


【解决方案1】:

我的建议是,不要这样做。相反,创建一个更智能的 books 数组来保存每本书的内部状态,然后使用它:

如果来自 API 的书籍数据作为 props 传递:

constructor(props) {
  super(props);

  state = {
    showSearchPage: false,
    // ES7 version
    books: this.props.books.map(book => {...book, status: "none"})
    // Non-ES7 version:
    // books: this.props.books.map(book => Object.assign({}, books, { status: "none" }))
  };

  // bind the event handler to the component
  this.handleChange = this.handleChange.bind(this);
}

以及下拉事件处理程序:

handleChange(index, event) {
  // grab a local copy of the book array that we will mutate
  let books = this.state.books;
  // only mutate the book that is being changed
  books[index].status = event.target.value;
  // safely pass the mutated copy into the state
  this.setState({ books });
}

最后,在你的渲染方法中:

{ this.state.books.map((book, index) => {
  return (
    <div key={index} className="book">
      ...other code here...
      <select
        value={book.status}
        onChange={(event) => this.handleChange(index, event)}>
      ...rest of your code...
    </div>
  );
})}

处理道具更新的生命周期方法:

componentWillReceiveProps(nextProps) {
  if (this.props.books !== nextProps.books) {
    this.setState({ books: nextProps.books.map(book => Object.assign({}, book, { status: "none" })) });
  }
}

编辑:将组件的this绑定添加到构造函数中的事件处理程序,并更改处理程序传递给onChange事件的方式。

编辑 2:添加了 componentWillReceiveProps 生命周期挂钩

【讨论】:

  • 首先,感谢您的回答,但我无法理解代码中发生了什么。您介意解释一下吗。对不起,我是 React 和 Javascript 的新手。所以,如果您将其分解,我将不胜感激。
  • 首先,您作为道具传递的书籍数组(我假设您从之前的 API 调用中获得)在构造函数中通过将每个单独的书籍值转换为包含书籍的对象来“增强”值和默认设置为“无”的状态(这是下拉菜单的默认值)。简而言之,我们为每本书关联了一个默认的开始状态。我们在构造函数中做的另一件事是将事件处理程序绑定到组件,以便稍后调用它时,this 正确地引用了组件。
  • 在渲染方法中,我们将被迭代的数组从this.props.books 更改为this.state.books(我们的增强数组)。这个很重要。然后,在 select 元素中,我们将默认值设置为正在迭代的书籍的当前状态为value = {book.status}。最后,我们将 handleChange 方法与 onChange 事件挂钩,并将当前图书索引作为附加参数传递。
  • 那么,对于一本书,如果我从下拉列表中选择一个值,那么所选值将是该特定书的状态值,对吧?所以,如果我想将书传递到不同的视图并根据状态从主视图中删除,我该怎么做?我的意思是我有 3 个不同的地方需要根据选择的值放置书
  • 最后,在事件处理程序handleChange 中,我们创建智能图书数组的本地副本(记住状态本身不是直接可变的),然后我们使用它的索引和设置更新图书的状态下拉设置的值(注意其他书籍不受影响,这非常重要)。最后,我们使用修改后的 books 数组更新状态。
猜你喜欢
  • 2015-02-18
  • 2021-01-08
  • 1970-01-01
  • 1970-01-01
  • 2019-11-18
  • 2016-08-25
  • 1970-01-01
  • 2021-10-21
  • 2019-11-21
相关资源
最近更新 更多