0

I'm creating a bookReads project (like goodreads) where you can keep tracks of your books. I have a table of books and every book is assigned a shelf. Every row has a dropdown which is used to change the shelf of the current book.

My problem is when I change the shelf of one book, it changes the shelf of all the books. I looked here, but this only talked about one particular value and not a bunch of values. I'm not sure what am I doing wrong here.

class ListBooks extends Component {
  state = {
    query: '',
    currentShelf: 'move',
    expanded: false,
    truncated: false,
    shelfNames: ['currentlyReading', 'wantToRead', 'read'],
    lines: 4
  }

  updateShelf = (event) => {
    this.setState({currentShelf: event.target.value})
  }

  updateQuery(query){
    this.setState({query: query})
  }

  render(){

    let showingBooks
    if(this.state.query){
      const match = new RegExp(escapeRegExp(this.state.query), 'i')
            showingBooks = this.props.books.filter((book) => match.test(book.title))
    } else {
      showingBooks = this.props.books
    }

    const {
            children,
            more,
            less,
            lines
        } = this.props;

        const {
            expanded,
            truncated
        } = this.state;

    showingBooks.sort(sortBy('title'))
    return(
      <div className="list-books">
        <div className="list-books-title">
          <h1>BookReads</h1>
        </div>
        <input type="text"
          placeholder="Search by title or author"
          value={this.state.query}
          onChange={(event) => this.updateQuery(event.target.value)}
          className="search-field"
          />
        <div className="list-books-content">
          <div>
            <Table striped bordered hover>
              <thead>
                <tr>
                  <th className="book-header">Book</th>
                  <th className="book-header">Author</th>
                  <th className="book-header"> Shelf </th>
                  <th></th>
                </tr>
              </thead>
              <tbody>{showingBooks.map((book)=>(
                  <tr key={book.id}>
                    <td className="bookShelfTable">
                      <div className="style">
                        <div className="book-cover" style={{ width: 128, height: 193, float: "left", marginRight: 10,
                          backgroundImage: "url(" + book.imageLinks.thumbnail + ")" }} />
                        <h4> {book.title} </h4>
                        <h6> {book.subtitle}</h6>
                      </div> <br />
                      <div>
                        {book.description}
                      </div>
                    </td>
                    <td>
                      <div> {book.authors} </div>
                    </td>
                    <td> {this.state.currentShelf}</td>
                    <td>
                      <div className="book-shelf-changer">
                        <select  value={this.state.currentShelf} onChange={this.updateShelf}>
                            <option value="move">Move to...</option>
                            <option value="currentlyReading">Currently Reading</option>
                            <option value="wantToRead">Want to Read</option>
                            <option value="read">Read</option>
                            <option value="none">None</option>
                        </select>

                         <i className="fa fa-times" onClick={() => this.props.onDeleteBook(book)}/>
                      </div>
                    </td>
                  </tr>
                ))}
              </tbody>
            </Table>
          </div>
        </div>
      </div>
    )
  }
}
abidishajia
  • 222
  • 1
  • 6
  • 15

2 Answers2

0

Instead of:

updateShelf = (event) => {
  this.setState({currentShelf: event.target.value})
}

Try just using regular ES6 method syntax:

updateShelf(event){
this.setState({currentShelf: event.target.value})

Edit: In that case, you definitely need to have a separate component/state for each book. Values which may change on an individual book basis should all be passed in as props to the book components and the initial value of these props are used in the component constructor to set the initial state values of each book component. When the dropdown changes, a method on the book component is called updating the state for only that book.

If you need a function in the book component that updates all of the books, that method should be created in the bookshelf object and a reference to this shelf method should also be passed in to the props of each book.

webnetweaver
  • 192
  • 8
0

You have a single currentShelf in your state, but all your books share it. You need to have a currentShelf state for each book. The easiest way to do this would be to make each book a stateful Book component, with a similar updateShelf method.

So everything inside your showingBooks.map callback would be the render method of your Book component.

Andy_D
  • 4,112
  • 27
  • 19