loading...

React Hooks with Async-Await

vinodchauhan7 profile image vinodchauhan7 ・2 min read

Picture this, You have text box which can give list books from google store based on what you type on it. If no book available on that particular search query than show 'No Book Found'. By default, it will always show 'Search for Books'.

Scenario's :
1) No Search : 'Search for Books'.
2) No Result : 'No Book Found'.
3) Found Books : 'Show list of books'.

In above scenarios', we want our result to update after searching the topic on Google API's. This clearly shows that we need to use promises or 'Async-await' to achieve the results. But here we want to make our custom hook which search for books when we hit the search button and show the results.

Now the question is Why we want hooks in this case. Answer is very simple, because we want to make our code cleaner and single liner on final usage. It must be not redundant i.e DRY(Don't Repeat Yourself).

function App() {
  const [search, setSearch] = React.useState("");
  const [query, setQuery] = React.useState("");
  return (
    <div className="App">
      <h1>Search for Books on any Topic</h1>
      <form
        onSubmit={e => {
          e.preventDefault();
          setQuery(search);
        }}
      >
        <label>Search : </label>
        <input type="text" onChange={e => setSearch(e.target.value)} />
        <input type="submit" value="search" />
      </form>

      <h1>List Result on {query}</h1>
    </div>
  );

Till now this is our simple code for getting the final search value in state 'query'. Now we make our custom Async hook to search on google Api's.

function useAsyncHook(searchBook) {
  const [result, setResult] = React.useState([]);
  const [loading, setLoading] = React.useState("false");

  React.useEffect(() => {
    async function fetchBookList() {
      try {
        setLoading("true");
        const response = await fetch(
          `https://www.googleapis.com/books/v1/volumes?q=${searchBook}`
        );

        const json = await response.json();
        // console.log(json);
        setResult(
          json.items.map(item => {
            console.log(item.volumeInfo.title);
            return item.volumeInfo.title;
          })
        );
      } catch (error) {
        setLoading("null");
      }
    }

    if (searchBook !== "") {
      fetchBookList();
    }
  }, [searchBook]);

  return [result, loading];
}

We cannot use 'async' keyword with 'useEffect' callback method. It will result in race conditions.

We are fetching our books from google api and then updating our 'setResult' state with book title. React.useEffect method will only run when our 'searchBook' got change.

//Updated App Component
function App() {
  const [search, setSearch] = React.useState("");
  const [query, setQuery] = React.useState("");
  const [result, loading] = useAsyncHook(query);
  return (
    <div className="App">
      <h1>Search for Books on any Topic</h1>
      <form
        onSubmit={e => {
          e.preventDefault();
          setQuery(search);
        }}
      >
        <label>Search : </label>
        <input type="text" onChange={e => setSearch(e.target.value)} />
        <input type="submit" value="search" />
      </form>

      {loading === "false" ? (
        <h1>Search for Books</h1>
      ) : loading === "null" ? (
        <h1>No Book Found</h1>
      ) : (
        result.map(item => {
          return <p>Book Title : {item}</p>;
        })
      )}
    </div>
  );
}

Alt Text

Src : Because Its One Life

Discussion

pic
Editor guide
Collapse
baavgai profile image
Baavgai

Thank you! This solved a major issue for me. Very helpful.

Collapse
nikhilknoldus profile image
Nikhil

It was useful for me, I wanted to use async in useEffect for api call.
Thanks

Collapse
avkonst profile image
Andrey

You might be interested in to consider Hookstate, which supports Promise in useState: hookstate.js.org/docs/asynchronous...