As I type in my search, the data will fetch from the API properly. The problem is that it keeps fetching several thousand times until the API throws an error. I successfully implemented an abortController, but I feel like there’s a less abrupt way to stop a fetch. I am using the useEffect hook based on the query and inventory state, but I don’t think my logic is very concise at all. Ideally, I need to fetch the data once and wait to fetch it again when the query state changes. Not necessarily the query and inventory as it is in the code, but that’s the only way it seemed to work.
Note: If there is nothing in the query, no results should be displayed.
Here’s the API (not sure if it’s needed for this question):
export const search = (query, maxResults) => fetch(`${api}/search`, { method: "POST", headers: { ...headers, "Content-Type": "application/json", }, body: JSON.stringify({ query, maxResults }), }) .then((res) => res.json()) .then((data) => data.books);
Here’s the Search component:
import { Link } from "react-router-dom"; import { useEffect, useState } from "react"; import * as BooksAPI from "./BooksAPI"; const SearchBooks = () => { const [query, setQuery] = useState(""); const [bookInventory, setBookInventory] = useState([]); useEffect(() => { let abortFetch = false; const getBooks = async () => { if (query.length !== 0) { const res = await BooksAPI.search(query, 20); setBookInventory(res); } if (query.length === 0) { setBookInventory(); } }; if (!abortFetch) { getBooks(); } return () => { abortFetch = true; } }, [query, bookInventory]) const updateSearchQuery = (query) => { setQuery(query); }; return ( <div className="search-books"> <div className="search-books-bar"> <Link to={"/"} className={"close-search"}>Close</Link> <div className="search-books-input-wrapper"> <input type="text" placeholder="Search by title, author, or ISBN" value={query} onChange={(e) => updateSearchQuery(e.target.value)} /> </div> </div> <div className="search-books-results"> { typeof bookInventory === 'object' && bookInventory.length > 0 ? <p>Your search results go here</p> : <p>Enter a valid search term to see results.</p> } </div> </div> ) } export default SearchBooks;
Advertisement
Answer
Because you have put bookInventory
in Second argument to useEffect
, and put setBookInventory
in useEffect
function.
This means every time bookInventory
changes, call useEffect
.
This’s the reason of that it keeps fetching.
The solution is to delete bookInventory
from Second argument to useEffect
:
useEffect(() => { ... }, [query]);