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>
);
}
Src : Because Its One Life
Top comments (5)
Thank you so much. I've also made a quick and minimal working example for future visitors here:
codesandbox.io/s/react-async-custo...
Loading is not necessary unless specifically needed, so in the sandbox above I've removed the loading from one of the hooks.
It was useful for me, I wanted to use async in useEffect for api call.
Thanks
Thank you! This solved a major issue for me. Very helpful.
You might be interested in to consider Hookstate, which supports Promise in useState: hookstate.js.org/docs/asynchronous...
Thank very much!!!