Apologies if this question has been asked before and solved, but I have been searching and haven't had much luck.
I have created an app where a person can search for a book and the results are returned. The problem I am having is when I enter a book title and select the search button an empty array is rendered and then an array with the proper results are returned but not rendered. When I select the search button again the proper results are rendered. I would like the correct results to be rendered on the first click.
I logged the results and it looks like the empty array is being rendered first instead of the correct results. I believe it could be due to the async nature of the API call.
Here is my code:
class App extends Component {
state = {
data: []
}
handleBookSearch = (book) => {
let data = utils.searchBooks(book);
this.setState({ data: data });
}
render() {
return (
<div className="">
<Banner
onSearch={this.handleBookSearch}
onRender={this.renderBooks} />
<div className="custom-margin">
<BookDisplay bookData={this.state.data} />
</div>
</div>
);
}
}
export default App;
class PostDisplay extends Component {
render() {
const { bookData } = this.props;
return (
bookData.map(book => (
<div>
<div className="cap-color">
<h4 className="card-header"><i className="fas fa-book fa-fw"></i>{book.title}</h4>
</div>
<div className="card-body">
<img src={book.thumbnail} alt={book.title} />
<h5 className="card-title margin-above"><b>Author:</b> {book.authors}</h5>
<h6><b>Publisher:</b> {book.publisher}</h6>
<h6><b>Published On:</b> {book.publishedDate}</h6>
<h6><b>Supported Languages:</b> {book.language}</h6>
<p className="card-text"><b>Description:</b> {book.description}</p>
<a href={book.link} target="_blank" rel="noopener noreferrer"
className="btn btn-primary cap-theme-project">Buy the book!</a>
</div>
</div>
))
);
}
}
export default PostDisplay;
class Banner extends Component {
constructor() {
super();
this.state = {
search: ''
};
}
updateSearch(event) {
const searchParam = event.target.value;
this.setState({ search: searchParam });
}
render() {
return (
< div className="title-banner" >
<h1 className="header-padding"><i className="fas fa-book fa-fw"></i><b>Google Library</b></h1>
<div className="container">
<div className="row justify-content-center">
<div className="col-12 col-md-10 col-lg-8 opacity">
<div className="card-body row no-gutters align-items-center">
<div className="col">
<input className="form-control form-control-lg form-control-borderless"
type="text" placeholder="Search for a book..." ref="searchQuery"
value={this.state.search}
onChange={this.updateSearch.bind(this)} />
</div>
<div className="col-auto">
<button onClick={() => this.props.onSearch(this.state.search)}
className="btn-margin btn btn-lg btn-primary"><i class="fas fa-search"></i></button>
</div>
</div>
</div>
</div>
</div>
</div >
);
}
}
export default Banner;
var books = require('google-books-search');
export let data = [];
export function searchBooks(title) {
books.search(title, function (err, results) {
if (!err) {
data = results;
} else {
console.log('ERROR: ' + err);
}
});
return data;
}