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