Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React onChange stuck in infinite loop

Tags:

reactjs

I have a React app that is set up to send an API request to a server to retrieve books that match the user's input.

The problem I have is that as soon as any query begins to be typed into the search field the app goes into a loop, sending hundreds of requests and is only stopped when the query is cleared from the search.

How can I limit it to one call per change in user query?

import React, { Component } from 'react'
import * as BooksAPI from './utils/BooksAPI'
// import Book from './Book';

export default class SearchBooks extends Component {

    state = {
        query: '',
        books: []
    }

    updateQuery = (query) => {
        this.setState(() => ({
            query: query
        }))
    }

    clearQuery = () => {
        this.updateQuery('')
    }

    searchBook = (query) => {
        if(query.length > 0)
        BooksAPI.search(query)
         .then(books => this.setState(currentState => ({
           books: currentState.books.concat(books)
          })));
    }

    render() {

        const { query, books } = this.state
        // const { onUpdateShelf } = this.props


        const showingBooks = query === ''
        ? books
        : this.searchBook(query)

        return(
            <div className="search-books">
                <div className="search-books-bar">
                  <a className="close-search" >Close</a>
                  <div className="search-books-input-wrapper">
                    <input
                        type="text"
                        placeholder="Search by title, author or subject"
                        value={query}
                        onChange={(event) => this.updateQuery(event.target.value)}
                    />
                  </div>
                </div>
                <div className="search-books-results">
                  <ol className="books-grid">
                    <li>
                      {/* { showingBooks.map((book) => (
                       <Book
                         key={book.id}
                         book={book}
                         updateShelf={onUpdateShelf} />
                        ))} */}
                    </li>
                  </ol>
                </div>
            </div>
        )
    }
}
like image 243
3therk1ll Avatar asked Oct 16 '22 18:10

3therk1ll


1 Answers

You are setting the state inside your render function with searchBook whenever query isn't an emtpy string. The setState() method triggers a re-render but since you are setting the state from inside the render function, it will keep calling itself.

I don't see why you need this function to be inside the render anyway. You want to search for a book whenever the query changes, but the query can only change on user input, so move the function there? Here is what I would do:

Change onChange={(event) => this.updateQuery(event.target.value)} to just onChange={this.updateQuery}. The event is passed to the function anyway.

Then, move your bookapi logic to your updateQuery function:

updateQuery = (e) => {
  if(e.target.value.length > 0)
    BooksAPI.search(query)
     .then(books => this.setState(currentState => ({
       query: e.target.value,
       books: currentState.books.concat(books)
      })));
}
like image 127
Chris Avatar answered Nov 24 '22 03:11

Chris