0

I am creating a React app that needs to update the state and call an API based on the option a user selects from the Select Box. As I am unable to place the function call in the <option></option> tags I need to retrieve the value from the option tags when onChange is called.

I have created a selectValue value in the app state to update and have tried to emulate the solution in the below post.

Using Props And State To Pass Value Of Select Box To Child Component React.JS The issue I am having, however, is that I do not know how to select and pass the value from the selected option.

I have tested it by hardcoding a value to be passed by onHandleSelectValue in the ListBooks.js file. When I do this the state updates as expected.

App.js

import React, { Component } from 'react'
import ListBooks from './ListBooks'
import * as BooksAPI from './utils/BooksAPI'
import { Route } from 'react-router-dom'

class BooksApp extends Component {
  state = {
    books: [],
    selectValue: 'wantToRead'
  }

  componentDidMount() {
    BooksAPI.getAll()
    .then((books) => {
      this.setState(() => ({
        books
      }))
    })
  }

  updateShelf = (book) => {
    const shelf = this.state.selectValue
    this.state.books.forEach(b => {
      if(b.id === book.id) {
        console.log('Shelf: ' + this.state.selectValue)
        b.shelf = shelf
        this.setState((currentState) => ({
          books: currentState.books
        }))
      }
    });
    BooksAPI.update(book, shelf)
  }

  handleSelectValue(option) {
    console.log('handleSelectValue: ' + option)
    this.setState((currentState) => ({
      selectValue: option
    }))
    console.log('handleSelectValue + selectValue: ' + option)
  }

  render() {
    return (
      <div>
        <Route exact path='/' render={() => (
          <ListBooks
          books={this.state.books}
          onUpdateShelf={this.updateShelf}
          onHandleSelectValue={this.handleSelectValue.bind(this)}
          />
        )} />
      </div>
    )
  }
}
export default BooksApp

ListBooks.js

import React, { Component } from 'react';
import PropTypes from 'prop-types'
import './App.css'

const shelves = [
  {
    key: 'currentlyReading',
    name: 'Currently Reading'
  },
  {
    key: 'wantToRead',
    name: 'Want To Read'
  },
  {
    key: 'read',
    name: 'Read'
  },
  // {
  //   key: '',
  //   name: 'None'
  // }
];

class ListBooks extends Component {

    static propTypes = {
       books: PropTypes.array.isRequired
    }

    state = {
        showSearchPage: false,
        query: ''
      }

    render() {

        const { books, onUpdateShelf, onHandleSelectValue } = this.props

        function getBooksForShelf(shelfKey) {
          return books.filter(book => book.shelf === shelfKey);
        }

        console.log(books);

        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">
                    {/*
                      NOTES: The search from BooksAPI is limited to a particular set of search terms.
                      You can find these search terms here:
                      https://github.com/udacity/reactnd-project-myreads-starter/blob/master/SEARCH_TERMS.md
                      However, remember that the BooksAPI.search method DOES search by title or author. So, don't worry if
                      you don't find a specific author or title. Every search is limited by search terms.
                    */}
                    <input type="text" placeholder="Search by title or author"/>
                  </div>
                </div>
                <div className="search-books-results">
                  <ol className="books-grid"></ol>
                </div>
              </div>
            ) : (
              <div className="list-books">
                <div className="list-books-title">
                  <h1>My Reads</h1>
                </div>
                <div className="list-books-content">
                  <div>
                    { shelves.map((shelf) => (
                      <div key={shelf.key} className="bookshelf">
                        <h2 className="bookshelf-title">{shelf.name}</h2>
                          <div className="bookshelf-books">
                            <ol className="books-grid">
                        <li>
                          { getBooksForShelf(shelf.key).map((book) => (
                            <div key={book.id} className="book">
                              <div className="book-top">
                               <div className="book-cover" style={{ width: 128, height: 193, backgroundImage: `url(${book.imageLinks.thumbnail})` }}></div>
                                <div className="book-shelf-changer"> 
                                 <select onChange={() => onUpdateShelf(book, onHandleSelectValue('read'))}>
                                  <option value="none" disabled >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>
                                </div>
                              </div>
                              <div className="book-title">{book.title}</div>
                             <div className="book-authors">{book.author}</div>
                            </div>
                            ))}
                          </li>
                        </ol>
                        </div> 
                      </div>
                    )) }
                  </div>
                </div>
                <div className="open-search">
                  <a onClick={() => this.setState({ showSearchPage: true })}>Add a book</a>
                </div>
              </div>
            )}
          </div>
        )
    }
}

export default ListBooks
Joshua
  • 3,055
  • 3
  • 22
  • 37
3therk1ll
  • 2,056
  • 4
  • 35
  • 64

1 Answers1

2

So using suggestion provided by @Praveen Kumar.

I removed the extra handlers and just changed the below line to pass the value from selected option as an argument.

<select onChange={(e) => onUpdateShelf(book, e.target.value)}>
3therk1ll
  • 2,056
  • 4
  • 35
  • 64