admin管理员组

文章数量:1435859

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 = ``;
    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>
  );
 }
}

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./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>
  );
 }
}
Share Improve this question edited Jul 3, 2020 at 0:57 0Valt 10.4k9 gold badges40 silver badges64 bronze badges asked Jul 8, 2019 at 13:38 Vishwanath BVishwanath B 892 silver badges11 bronze badges 2
  • Maybe use this: stackoverflow./questions/26017364/… – Roknix Commented Jul 8, 2019 at 13:42
  • here is a few ideas that might help you both optimize and solve the issue. First of, trim, always trim, secondly if the .length after trim is less a single character, do not send the request at all. If a trimmed string doesn't contain at least one character it is essentially '' and thus equal to not having typed anything. Lastly, debounce the requests so long as the user is typing, no need to DDOS the API – Dellirium Commented Jul 8, 2019 at 13:45
Add a ment  | 

4 Answers 4

Reset to default 2

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.

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

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./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.

I think the code should be:

 onChange = async (e) => {
   await this.setState({ searchTerm: e.target.value });
   this.fetchBooks();   
  };

本文标签: javascriptHow do I prevent empty values in my search barin ReactStack Overflow