We typically use fetch to make network requests for JSON data.
Most apps will access the internet in one way or another. Today we'll be looking at one of the most common forms of this: calling an API and handling a JSON reponse object using fetch.
React Native supports most of the same networking APIs as web browsers, like XMLHttpRequest and fetch. This means that libraries you might already be familiar with, like superagent or axios, should work out-of-the-box. Additionally, there are third-party libraries for supporting more advanced use cases, like Apollo for GraphQL.
But first...
async and
await
If you already know how to use the JavaScript keywords async and await, skip ahead to the next section. Otherwise, here's a quick primer.
The keywords async and await are a useful JavaScript language feature for handling control flow in asynchronous programs. These leverage the Promise class under the hood, and are an alternative to many patterns that previously used callbacks.
To use these:
- We write
async before a function definition. This forces the function to return a Promise. No matter what we return from an async function, the value will be wrapped in a promise if it isn't already.
- We write
await before a Promise to pause the execution of the current function until the Promise is resolved or rejected. This pause is non-blocking, so other code can still run if triggered by a browser/node event. We can only use await within an async function.
Here's an example:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getNumber() {
return 42;
}
async function main() {
console.log("hello");
await sleep(1000);
console.log("world");
const number = await getNumber();
console.log(number);
}
main();
In this example, we created a sleep function that waits for ms milliseconds using setTimeout. We also created a getNumber function that doesn't actually do anything asynchronous, but still wraps its result in a Promise since it's marked as async. Lastly, we call these from a main function using await. Sometimes we may ignore the result of an await-ed function, like sleep. Other times we may use the value, as in the case of getNumber.
If an error is thrown in an async function, the function will then return Promise.reject(error). If an await-ed Promise is rejected, the error value is thrown -- so most await calls should happen in a try/catch block.
We commonly use async and await for network calls, as we'll see now!
We typically use fetch to make network requests for JSON data.
Here's an example where we fetch a list of posts from a placeholder data API:
async function fetchPosts() {
const result = await fetch("https://jsonplaceholder.typicode.com/posts");
const posts = await result.json();
return posts;
}
The call to fetch returns a Promise, so we use await to pause execution of the function until the Promise resolves. After that, we convert the response to a JavaScript object using result.json(), which is also asynchronous and returns a Promise. Finally, we return the result from our function.
Here's what a component that uses fetchPosts might look like:
Fetching data from the internet is great, but one of the big advantages of mobile apps is that we can make the data available offline. To do that, we'll need to persist the data we fetch. Check out tomorrow's article to see how!