Reputation: 3441
I have a BooksAPI file that contains the following search method:
export const search = (query) =>
fetch(`${api}/search`, {
method: 'POST',
headers: {
...headers,
'Content-Type': 'application/json'
},
body: JSON.stringify({ query })
}).then(res => res.json())
.then(data => data.books)
I'm trying to make it so that results start showing up when I type into the search bar, and I also want no books to show when the search bar is empty.
I have it working so that I can display results with the initial search, but if I try to backspace to type in a new term, I get a cannot read property map of undefined
error, which makes sense, but I'm not sure how to address this. I can only do a new search if I refresh the page.
Any help is greatly appreciated.
This is what I have so far for App.js:
class BooksApp extends React.Component {
state = {
books: []
}
componentDidMount() {
BooksAPI.getAll()
.then((books) => {
this.setState(() => ({
books
}))
})
}
render() {
return (
<div className="app">
<div className="list-books">
<div className="list-books-title">
<h1>MyReads</h1>
</div>
<Route exact path="/" render={() => (
<BookList
books={this.state.books}
/>
)} />
<Route path="/search" component={Search} />
<Route path="/search" render={({ history }) => (
<Search
onSearch={(query) => {
this.search(query)
history.push('/')
}}
/>
)} />
<div className="open-search">
<Link to="/search">Add a book</Link>
</div>
</div>
</div>
)
}
}
export default BooksApp
And here is my Search component:
class Search extends Component {
state = {
query: '',
books: []
}
search = (query) => {
BooksAPI.search()
.then((books) => {
this.setState(() => ({
query,
books
}))
})
}
render() {
const { query, books } = this.state
return (
<div className="search-books">
<div className="search-books-bar">
<Link
className="close-search"
to='/'>Close
</Link>
<div className="search-books-input-wrapper">
<input
type="text"
onChange={(event) => this.search(event.target.value)}
placeholder="Search by title or author"
value={query}
/>
</div>
</div>
<div className="search-books-results">
<ol className="books-grid">
{books.map((book) => (
<li>
<div>
<p>{book.title}</p>
<p>{book.author}</p>
</div>
</li>
))}
</ol>
</div>
</div>
)
}
}
export default Search;
Upvotes: 0
Views: 1578
Reputation: 2289
I had similar functionality I wanted to implement recently, I would recommend going to a library such as react-select to solve this problem rather than reinventing the wheel.
Upvotes: 1