Biii
Biii

Reputation: 3441

Search bar functionality for book API in React

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

Answers (1)

Paul McLoughlin
Paul McLoughlin

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

Related Questions