Reputation: 397
Full code here
I am getting errors for udpateShelf is not defined, but Changeshelf is imported and it has properties assigned in the function, I'm so confused, why am I still getting undefined errors? I feel like I'm not understanding fully how react passes props through the components, if someone cane explain that better I feel that will help me with creating different components or functions for this app.
Bookshelf.js
import React, { Component } from 'react'
import * as BooksAPI from './BooksAPI'
import PropTypes from 'prop-types'
import Books from './Books.js'
import logo from '../icons/logo.svg'
import { Link } from 'react-router-dom'
import ChangeShelf from "./ChangeShelf.js"
const shelves = [
{ key: 'currentlyReading',
name: 'Currently Reading' },
{ key: 'wantToRead',
name: 'Want to Read' },
{ key: 'read',
name: 'Read' }
]
export default class Bookshelf extends Component {
static propTypes = {
book: PropTypes.object.isRequired,
books: PropTypes.array.isRequired,
updateShelf: PropTypes.func.isRequired
}
render() {
const { book, books, shelfkey } = this.props;
return (
<div className="list-books">
<div className="react-app">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">React bookshelf app</h1>
</header>
</div>
<div className="list-books-title">
<h1>my bookshelf</h1>
</div>
<div className="list-books-content">
{shelves.map(shelf => (
<div key={ shelf.key } className="bookshelf">
<h2 className="bookshelf-title">{ shelf.name }</h2>
{ updateShelf(shelfkey).length === 0 ?
(<div>no books on this shelf</div>)
:
(<div className="bookshelf-books">
<ol className="books-grid">
<li>
{updateShelf(shelf.key).map(book => (
<Books
book={book}
books={books}
key={book.id}
onupdateShelf={this.UpdateShelf}
/>
))}
</li>
</ol>
</div>
)
}
</div>
))}
<Link to="/search" className="open-search">Add a book</Link>
</div>
</div>
)
}
}
Changeshelf.js
import React, { Component } from 'react'
import * as BooksAPI from './BooksAPI'
import PropTypes from 'prop-types'
import Books from './Books.js'
export default class ChangeShelf extends Component {
static propTypes = {
book: PropTypes.object.isRequired,
books: PropTypes.array.isRequired,
onChangeShelf: PropTypes.func.isRequired
}
updateShelf = (book, newShelf) => {
this.setState(previousState => {
const newBooks = previousState.books.filter((b) => b.id !==
book.id)
newBooks.push({ book, newShelf })
return { books: newBooks }
})
BooksAPI.update(book, newShelf)
}
moveBook = (shelf) => {
const { books } = this.props
return books.filter(book => book.shelf === shelf)
}
render() {
const { book, books, updateShelf } = this.props
return (
<div className="book-shelf-changer">
<select onChange={(event) => updateShelf(book,
event.target.value)}>
<option value="move" disabled>Move to...</option>
<option value="Currently Reading">Currently Reading</option>
<option value="Want To Read">Want to Read</option>
<option value="Read">Read</option>
<option value="none">None</option>
</select>
</div>
)
}
}
Upvotes: 2
Views: 72
Reputation: 8418
I'll try to explain ;)
Component App
loads books and saves data in state;
render uses imported component <Bookshelf />
;
Bookshelf gets this.state.books
as books
prop and not existing (in App) handler/method this.updateShelf
as onUpdateShelf
prop;
In Bookshelf
you can use them by this.props.books
and this.props.onUpdateShelf
. This is passing handler by prop. It lets call method in parent from child. It can be passed/used deeply. Called method, async processes usually ends with new state (setState) which forces rerender (updating props passed to childs).
For simplicity const { book, books, shelfkey } = this.props;
(in render) these props can be used by local identifiers book
(instead this.props.book
), books
, shelfkey
.
Problems:
no book
passed;
no shelfkey
passed;
missing book
and updateShelf
defined by propTypes
as required (we have onUpdateShelf
instead, but passed missing method, undefined);
updateShelf
not defined, not passed (should be this.props.updateShelf
), not defined locally (should be this.updateShelf
);
updateShelf
used (expected) there as fn returning array while in ChangeShelf
as event handler;
You can move updateShelf
method from ChangeShelf
to App
and pass it as prop to Bookshelf, Search and deeper when needed.
Upvotes: 1