Reputation: 89
So, I am building a book finder in React using Google Books API.
The user types the name of the book he/she wants to search, in the input field, and the value typed in the input is appended to the end of the API url.
Basically, the API is called every single time the user types something in the input field, because I want display some of the results in a dropdown below the search bar. The problem is that, if the user hits spacebar, which is an empty string, I get a HTTP 400
error, specifically this:
Error: Request failed with status code 400
at createError (createError.js:17)
at settle (settle.js:19)
at XMLHttpRequest.handleLoad (xhr.js:60)
If I call .trim()
on the input value, then that just prevents a user from typing anything at all. I'm kind of confused what to do right now. Also, is calling the API everytime the input value changes an expensive operation? This is what I've tried so far:
import React, { Component } from 'react';
import axios from 'axios';
export default class BookSearchForm extends Component {
state = {
searchTerm: ''
};
fetchBooks = () => {
let apiURL = `https://www.googleapis.com/books/v1/volumes`;
axios
.get(`${apiURL}?q=${this.state.searchTerm}`)
.then(res => console.log(res))
.catch(err => console.log(err));
};
onChange = e => {
this.fetchBooks();
this.setState({ searchTerm: e.target.value });
};
render() {
return (
<div className="container">
<form autoComplete="off">
<input
className="search-bar"
type="search"
placeholder="Search for books"
onChange={this.onChange}
value={this.state.searchTerm}
/>
</form>
</div>
);
}
}
Upvotes: 3
Views: 3651
Reputation: 282
You can try below code.
onChange = e => {
let value = e.target.value;
this.fetchBooks(value.trim());
this.setState({ searchTerm: e.target.value });
};
fetchBooks = (str) => {
if (str) {
let apiURL = `https://www.googleapis.com/books/v1/volumes`;
axios
.get(`${apiURL}?q=${str}`)
.then(res => console.log(res))
.catch(err => console.log(err));
}
};
Yes, calling API on every input change is expensive. You should use debouncing.
Upvotes: 1
Reputation: 118
You could validate the user input and don't allow empty strings.
Also, is calling the API everytime the input value changes an expensive operation?
Likely yes. You might want to debounce or throttle your requests
Upvotes: 1
Reputation: 166
I think the code should be:
onChange = async (e) => {
await this.setState({ searchTerm: e.target.value });
this.fetchBooks();
};
Upvotes: 0
Reputation: 4464
You can replace whitespaces using the \s
regex.
You may also want to fetch after the state is updated (callback of setState) :
onChange = e => {
this.setState(
{ searchTerm: e.target.value.replace(/\s/g, '') },
() => {
this.fetchBooks();
}
);
};
.replace(/\s/g, '')
will replace all whitespaces (including tab, newline etc...) from the string by an empty char (''
), making whitespaces from user inputs doing nothing.
Upvotes: 2