最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - How do I prevent empty values in my search bar, in React? - Stack Overflow

matteradmin6PV0评论

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();   
  };
Post a comment

comment list (0)

  1. No comments so far