React:rendering API can't read length

I’m trying to rendering Google Books API, just the user have to write in a input field to find a book and the title appers. But when the user delete all the field, the apps colapse and send me this error message
Cannot read property ‘length’ of undefined. And i been trying using conditional like " if length === 0 " but i recive same error.
CodeSandBox: https://codesandbox.io/s/busy-banzai-jcc69?file=/src/components/Add.js
Error message:


Code:

import React, { useState } from "react";

export const Add = () => {
  // Hooks~
  const [query, setQuery] = useState("");
  const [results, setResults] = useState([]);

  // Functions =>
  const handleChange = (e) => {
    e.preventDefault();

    setQuery(e.target.value);

    fetch(
      `https://www.googleapis.com/books/v1/volumes?q=${e.target.value}&key=AIzaSyDmmCThZovxSFYPvCUaUB6h4c5gYCJeUnw`
    )
      .then((res) => res.json())
      .then((data) => {
        !data.errors ? setResults(data.items) : setResults([]);
      });
  };

  return (
    <div>
      <div>
        <div>
          {/* Searchbar */}
          <div>
            <input
              type="text"
              placeholder="Search for a book"
              value={query}
              onChange={handleChange}
            />
          </div>

          {/* Rendering Fetch Data */}
          {results.length > 0 && (
            <ul>
              {results.map((book) => (
                <li key={book.id}>
                  <h3>{book.volumeInfo.title}</h3>
                </li>
              ))}
            </ul>
          )}
        </div>
      </div>
    </div>
  );
};

The error says that it cannot read property length of undefined, so it means that somehowe results is undefined.

It’s initialized as an empty array so nothing wrong here.

The only other place where you update the results is after fetching the data here:

fetch("...")
  .then(res => res.json())
  .then(data => {
    !data.errors ? setResults(data.items) : setResults([]);
  });

First thing I would do is check how does the data object look like by console.logging it.

Gives me this error on codesandbox
message: "API key not valid. Please pass a valid API key."

Try replacing the fetch link with https://www.googleapis.com/books/v1/volumes?q=${e.target.value}&key=AIzaSyDmmCThZovxSFYPvCUaUB6h4c5gYCJeUnw

You will find the problem if you hit this api via postman or check your console while emptying your input. It says message: "Missing query." Now what you are doing is hitting the api as soon as input is changed (while adding a letter or deleting it). So as soon as you empty the input, it fires the request with missing query and thus the error. You should create a function where the api should be triggered only when input has at least one letter. Thus solving your problem.

1 Like

I found a simple solution, using only {results && (

    ....) But it would nice if somebody explain what really happends.

Actually the problem with results length is still there. It’s just not visible because the API call gets executed without any errors.

But if there is an error it fails again like it did before.

The problem is here:

.then((data) => {
  !data.errors ? setResults(data.items) : setResults([]);
})

There is no property errors on the data object. It’s error.

Because of that this !data.errors is basically !undefined so it always evaluates to true. Hence whether there is error or no you always set results to data.items and when there is an error it will be undefined so it won’t be possible to access length on it.

1 Like