VOOZH about

URL: https://blog.logrocket.com/data-fetching-react-native/

โ‡ฑ Data fetching with React Native - LogRocket Blog


2021-07-05
2937
#react native
Hussain Arif
56913
๐Ÿ‘ Image

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

React Native is an amazing library for developers looking to build mobile apps with ease. It provides an efficient way of displaying information to the frontend. But how do we get the data so that our components can render it?

๐Ÿ‘ Data Fetching with React Native

In this article, you will learn how to fetch data from an API and display it to the user. Weโ€™ll cover several approaches with comprehensive code samples to help you determine the best method for your app.

Weโ€™ll cover the following options for fetching data in React Native:

To show data procurement in React Native, weโ€™ll construct a basic app that fetches a list of items from Coffee API. Moreover, we will use the NativeBase UI library for rendering our data to the client.

In the end, your example app will look like this:

๐Ÿ‘ Data Fetching in React Native Final Product

You can get the full source code for this application from this GitHub repository.

๐Ÿš€ Sign up for The Replay newsletter

The Replay is a weekly newsletter for dev and engineering leaders.

Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.

Getting started

Project initialization

To scaffold a React Native project with Expo, run the following terminal command:

expo init reactnative-data-fetching

Getting dependencies

Here, we will install the following modules:

  • @apollo/client : for making GraphQL queries
  • graphql: peer dependency for Apollo Client
  • native-base, styled-components, styled-system: to use the NativeBase library

To acquire these packages, write the following terminal command:

npm i @apollo/client graphql native-base styled-components styled-system 

As the next step, install NativeBaseโ€™s peer dependencies like so:

expo install react-native-svg
expo install react-native-safe-area-context

When thatโ€™s done, itโ€™s time to demonstrate data fetching.

When do you need to fetch data?

There are three reasons youโ€™d need to fetch data:

  • Loading data on the componentโ€™s first render
  • Fetching the data and rendering it when the user clicks a button
  • Loading data at separate time intervals

We will write code for each of these use cases.

Using the inbuilt Fetch API

The Fetch API is the most common method of retrieving data because it comes bundled with React.

Data fetching on mount

In your components folder, create a file called CoffeeAutonomous.js. There, start by writing the following code:

import React, { useState, useEffect } from "react";
import { Box, FlatList, Center, NativeBaseProvider, Text } from "native-base";

export default function CoffeeAutonomous() {
 const [data, setData] = useState([]);
 const [loading, setLoading] = useState(true);

 const fetchData = async () => {
 const resp = await fetch("https://api.sampleapis.com/coffee/hot");
 const data = await resp.json();
 setData(data);
 setLoading(false);
 };

 const renderItem = ({ item }) => {
 return (
 <Box px={5} py={2} rounded="md" bg="primary.300" my={2}>
 {item.title}
 </Box>
 );
 };

Letโ€™s dissect this code piece by piece.

In the beginning, we created two Hooks called data and loading. The data Hook will hold fetched data and loading will tell the user if the data is on its way.

Furthermore, the fetchData method will use the fetch method to get the response from the server and then store it into the data Hook. In the end, we set the loading Hook to false. Other than that, the renderItem function will display each itemโ€™s title field.

Now we need to render it. To do so, add the following code in the same file:

useEffect(() => {
 fetchData();
}, []);

return (
 <NativeBaseProvider>
 <Center flex={1}>
 <Box> Fetch API</Box>
 {loading && <Box>Loading..</Box>}
 {data && (
 <FlatList
 data={data}
 renderItem={renderItem}
 keyExtractor={(item) => item.id.toString()}
 />
 )}
 </Center>
 </NativeBaseProvider>
);
}

Notice that we left the useEffect dependency array empty. This means that React will call the fetchData method on the first render. Next, we used the FlatList component to display the contents of the data array.

Finally, go to App.js and render the CoffeeAutonomous component:

import React from "react";
import CoffeeAutonomous from "./components/CoffeeAutonomous";
export default function App() {
 return <CoffeeAutonomous />;
}

This will be the output:

๐Ÿ‘ Fetch API Fetching on Mount

In the next section, you will learn how to render data when the user clicks a button.
In the end, CoffeeAutonomous.js should look like this:

import React, { useState, useEffect } from "react";
import { Box, FlatList, Center, NativeBaseProvider, Text } from "native-base";

export default function CoffeeAutonomous() {
 const [data, setData] = useState([]);
 const [loading, setLoading] = useState(true);

 const fetchData = async () => {
 const resp = await fetch("https://api.sampleapis.com/coffee/hot");
 const data = await resp.json();
 setData(data);
 setLoading(false);
 };

 useEffect(() => {
 fetchData();
 }, []);

 const renderItem = ({ item }) => {
 return (
 <Box px={5} py={2} rounded="md" bg="primary.300" my={2}>
 {item.title}
 </Box>
 );
 };

 return (
 <NativeBaseProvider>
 <Center flex={1}>
 <Box> Fetch API</Box>
 {loading && <Box>Loading..</Box>}
 {data && (
 <FlatList
 data={data}
 renderItem={renderItem}
 keyExtractor={(item) => item.id.toString()}
 />
 )}
 </Center>
 </NativeBaseProvider>
 );
}

Data fetching on button click

Create a file called CoffeeClick.js and write the following code:

import React, { useState } from "react";
import { Box, FlatList, Center, NativeBaseProvider, Button } from "native-base";

export default function CoffeeClick() {

 const [data, setData] = useState(null);
 const [visible, setVisible] = useState(true);

 const fetchData = async () => {
 const resp = await fetch("https://api.sampleapis.com/coffee/hot");
 const data = await resp.json();
 setData(data);
 setVisible(false);
 };

 const renderItem = ({ item }) => {
 return (
 <Box px={5} py={2} rounded="md" bg="primary.300" my={2}>
 {item.title}
 </Box>
 );
 };
}

The first part of this code is similar to that of CoffeeAutonomous. The only difference is that we have declared a visible Hook. Other than that, in the fetchData function, we told React that if the data is now present, then set the visible Hook to false.

To render the UI, append the following code:

return (
 <NativeBaseProvider>
 <Center flex={1}>
 {visible && <Button onPress={() => fetchData()}>Press</Button>} 
 {data && (
 <FlatList
 data={data}
 renderItem={renderItem}
 keyExtractor={(item) => item.id.toString()}
 />
 )}
 </Center>
 </NativeBaseProvider>
 );
}

On line 4, we used conditional rendering. This will hide the component when clicked.


Over 200k developers use LogRocket to create better digital experiences

๐Ÿ‘ Image
Learn more โ†’

๐Ÿ‘ Fetch API Fetching on Button Click

In the next section, you will learn how to fetch data in regular intervals.

Our CoffeeClick.js file should look like this:

import React, { useState } from "react";
import { Box, FlatList, Center, NativeBaseProvider, Button } from "native-base";

export default function CoffeeClick() {
 const [data, setData] = useState(null);
 const [visible, setVisible] = useState(true);

 const fetchData = async () => {
 const resp = await fetch("https://api.sampleapis.com/coffee/hot");
 const data = await resp.json();
 setData(data);
 setVisible(false);
 };

 const renderItem = ({ item }) => {
 return (
 <Box px={5} py={2} rounded="md" bg="primary.300" my={2}>
 {item.title}
 </Box>
 );
 };

 return (
 <NativeBaseProvider>
 <Center flex={1}>
 {visible && <Button onPress={() => fetchData()}>Press</Button>}
 {data && (
 <FlatList
 data={data}
 renderItem={renderItem}
 keyExtractor={(item) => item.id.toString()}
 />
 )}
 </Center>
 </NativeBaseProvider>
 );
}

Fetching data in intervals

This step is straightforward. Create a file called CoffeeInterval.js.

After that, copy the code from CoffeeAutonomous.js and paste it. We will make changes to add interval functionality.

In CoffeeInterval.js, change your useEffect handler:

useEffect(() => {
 fetchData();
 const dataInterval = setInterval(() => fetchData(), 5 * 1000);

 return () => clearInterval(dataInterval);
}, []);

In this piece of code, we used the setInterval function to run the fetchData method every 5 seconds. Later on, we specified that if this component gets deleted from the tree, then clear this interval. This will prevent memory leaks.

Thatโ€™s all there is to it! Your code should run without any issues:

๐Ÿ‘ Fetching Data in Intervals

Your CoffeeInterval.js file should look like this:

import React, { useState, useEffect } from "react";
import { Box, FlatList, Center, NativeBaseProvider, Text } from "native-base";

export default function CoffeeInterval() {
 const [data, setData] = useState([]);
 const [loading, setLoading] = useState(true);

 const fetchData = async () => {
 const resp = await fetch("https://api.sampleapis.com/coffee/hot");
 const data = await resp.json();
 setData(data);
 setLoading(false);
 };

 useEffect(() => {
 fetchData();
 const dataInterval = setInterval(() => fetchData(), 5 * 1000);
 return () => clearInterval(dataInterval);
 }, []);

 const renderItem = ({ item }) => {
 return (
 <Box px={5} py={2} rounded="md" bg="primary.300" my={2}>
 {item.title}
 </Box>
 );
 };

 return (
 <NativeBaseProvider>
 <Center flex={1}>
 {loading && <Box>Loading..</Box>}
 {data && (
 <FlatList
 data={data}
 renderItem={renderItem}
 keyExtractor={(item) => item.id.toString()}
 />
 )}
 </Center>
 </NativeBaseProvider>
 );
}

Using Axios

One alternative to Fetch is Axios, which is compatible for Node, React and React Native. In addition to making GET requests, this module can even allow you to make POST, PUT and DELETE requests.

To install the package, run this terminal command:

npm install axios

Fetching with Axios

To retrieve data using the Axios library, write the following code:

import axios from "axios"
export default function App() {
 const fetchData = () => {
 const baseURL = "https://api.sampleapis.com/coffee";
 axios.get(`${baseURL}/hot`).then((response) => console.log(response.data));
 };
 useEffect(() => {
 fetchData();
 }, []);
}

In this piece of code, we instructed Axios is perform a GET request to the Coffee API and log out the response.

๐Ÿ‘ Axios Coffee API GET Request

We have a whole post covering data fetching with Axios and React Native if you want in-depth information on using Axios to manage your API requests.

Fetching data with Apisauce

One alternative to Fetch is Axios. But since Axios is not compatible with React Native, we can use Apisauce instead. It is a wrapper for Axios and can even allow you to make POST, PUT, and DELETE requests.

To install the package, run this terminal command:

npm i apisauce 

The simple way to fetch data with Apisauce

This is how you can make requests with the Apisauce library:

import React from "react";
import { useEffect } from "react";
import { create } from "apisauce";

//file name: SauceExample.js
//extra code removed for brevity purposes

//The baseURL will be our starting point.
const api = create({
 baseURL: "https://api.sampleapis.com/coffee",
});

const fetchData = () => {
 //make request to baseURL + '/hot'
 api
 .get("/hot")
 .then((response) => response.data)
 .then((data) => console.log(data));
};

useEffect(() => {
 fetchData();
}, []);

In the end, we told React to execute the fetchData function on the first render. This will log out the APIโ€™s response to the terminal.

This will be the output:

๐Ÿ‘ Apisauce FetchData

We will use Hooks to render this data.

Using Apisauce with Hooks

In components/SauceExample.js, write the following code:

import { FlatList, Box, NativeBaseProvider, Center } from "native-base";
import React from "react";
import { useEffect } from "react";
import { create } from "apisauce";
import { useState } from "react";

export default function SauceExample() {
 const [data, setData] = useState([]);
 const api = create({
 baseURL: "https://api.sampleapis.com/coffee",
 });

 const fetchData = () => {
 //make request to baseURL + 'hot'
 api
 .get("/hot")
 .then((response) => response.data)
 .then((data) => setData(data));
 };

 const renderItem = ({ item }) => {
 return (
 <Box px={5} py={2} rounded="md" bg="primary.300" my={2}>
 {item.title}
 </Box>
 );
 };

 useEffect(() => {
 fetchData();
 }, []);

 return (
 <NativeBaseProvider>
 <Center flex={1}>
 <Box> Using Apisauce </Box>
 {data && (
 <FlatList
 data={data}
 renderItem={renderItem}
 keyExtractor={(item) => item.id.toString()}
 />
 )}
 </Center>
 </NativeBaseProvider>
 );
}

This will be the output:

๐Ÿ‘ Using Apisauce with Hooks

If you want to get data from the iced route, all you need to do is alter a line within your fetchData function:

const fetchData = () => {
 //make request to baseURL + 'iced'
 api
 .get("/iced")
 .then((response) => response.data)
 .then((data) => setData(data));
};

๐Ÿ‘ Using Apisauce Iced

Using async/await with Apisauce

Want to use async and await in your code? No problem. You can write your code like this:

const fetchData = async () => {
 //make request to baseURL + 'iced'
 const response = await api.get("/iced");
 setData(response.data);
};

Using render props to render data

Props in React allow for modularity and cleanliness in our code. For example, to render data, we wrote the following:

return (
 <NativeBaseProvider>
 <Center flex={1}>
 {data && (
 <FlatList
 data={data}
 renderItem={renderItem}
 keyExtractor={(item) => item.id.toString()}
 />
 )}
 </Center>
 </NativeBaseProvider>
);

To shorten this block, you can use render props.

Create a custom component called DataRenderer.js:

import { FlatList, Box } from "native-base";
import React from "react";

export default function DataRenderer({ data }) {

 const renderItem = ({ item }) => {
 return (
 <Box px={5} py={2} rounded="md" bg="primary.300" my={2}>
 {item.title}
 </Box>
 );
 };

 return (
 <FlatList
 data={data}
 renderItem={renderItem}
 keyExtractor={(item) => item.id.toString()}
 />
 );
}

Use it in your other files like so:

 return (
 <NativeBaseProvider>
 <Center flex={1}>{data && <DataRenderer data={data} />}</Center>
 </NativeBaseProvider>
 );

Our code looks cleaner! The output should be the same as before.

๐Ÿ‘ Rendering Data with Props

Data fetching with GraphQL and Apollo client

Why use GraphQL?

GraphQL is a technology that is completely different from REST while still maintaining ease of use.

For example, to make a standard request to our Coffee API using REST, you would do the following:

const response = await fetch(https://api.sampleapis.com/coffee/hot)
//further code ...

This would give the following response:

๐Ÿ‘ Coffee API Using REST

Even though this is fine, there is a minor flaw. Our app only needs the title field. The rest of the data is unnecessary to us.

This is where GraphQL comes in. To retrieve only the title and data fields of our items, we will perform the following query:

query HotCoffees{
 allHots {
 title
 id
 }
}

This will be the response from the server:

๐Ÿ‘ Image

To summarize, GraphQL only gives you the data that you require.

GraphQL sample usage

In your components folder, create a file called CoffeeGraphQL.js. Here, start by writing the following piece of code:

import {
 ApolloClient,
 InMemoryCache,
 ApolloProvider,
 useQuery,
 gql,
} from "@apollo/client";
import { Box, Center, NativeBaseProvider } from "native-base";
import React from "react";
import DataRenderer from "./DataRenderer";

//connect to GraphQL server:
const client = new ApolloClient({
 uri: "https://api.sampleapis.com/coffee/graphql",
 cache: new InMemoryCache(),
});

function RenderQuery() {
//define our query
 const query = gql`
 query HotCoffees {
 allHots {
 title
 id
 }
 }
 `;
 //make a query
 const { loading, error, data } = useQuery(query);
 if (error) console.log(error);

 return (
 <NativeBaseProvider>
 <Center flex={1}>
 <Box> Using GraphQL </Box>
 {loading && <Box>Loading data.. please wait</Box>}
 {data && <DataRenderer data={data.allHots} />}
 </Center>
 </NativeBaseProvider>
 );
}

A few inferences from this code:

  • The client variable connects our application to the GraphQL server
  • Later on, we made a query to get the title and id fields
  • If an error occurs, log it out to the console
  • When data has loaded, display it to the UI

As a final step, we now have to bind our RenderQuery component to our GraphQL client.

To do so, add the following code in CoffeeGraphQL.js:

export default function CoffeeGraphQL() {
 return (
 <ApolloProvider client={client}>
 <RenderQuery />
 </ApolloProvider>
 );
}

This will be the result:

๐Ÿ‘ GraphQL Coffee API

Your CoffeeGraphQL.js file should look like this:

import {
 ApolloClient,
 InMemoryCache,
 ApolloProvider,
 useQuery,
 gql,
} from "@apollo/client";
import { Box, Center, NativeBaseProvider } from "native-base";
import React from "react";
import DataRenderer from "./DataRenderer";

//connect to GraphQL server:
const client = new ApolloClient({
 uri: "https://api.sampleapis.com/coffee/graphql",
 cache: new InMemoryCache(),
});CoffeeClass

function RenderQuery() {
 const query = gql`
 query HotCoffees {
 allHots {
 title
 id
 }
 }
 `;
 //make a query
 const { loading, error, data } = useQuery(query);
 if (error) console.log(error);
 return (
 <NativeBaseProvider>
 <Center flex={1}>
 <Box>Using GraphQL</Box>
 {loading && <Box>Loading data.. please wait</Box>}
 {data && <DataRenderer data={data.allHots} />}
 </Center>
 </NativeBaseProvider>
 );
}

export default function CoffeeGraphQL() {
 return (
 <ApolloProvider client={client}>
 <RenderQuery />
 </ApolloProvider>
 );
}

Fetching data with class components

While modern React favors the use of functional components, the option to build your app with class components is still present. This is useful in maintaining legacy React Native code.

Create a class called CoffeeClass.js and write the following block:

import { Center, NativeBaseProvider, Box } from "native-base";
import React, { Component } from "react";
import DataRenderer from "./DataRenderer";

export default class CoffeeClass extends Component {
 constructor(props) {
 super(props);
 this.state = {
 data: [],
 };
 }
 componentDidMount() {
 this.fetchUsersAsync();
 }

 fetchUsersAsync() {
 const URL = "https://api.sampleapis.com/coffee/hot";
 fetch(URL)
 .then((response) => response.json())
 .then((list) => this.setState({ data: list }));
 }
 render() {
 return (
 <NativeBaseProvider>
 <Center flex={1}>
 <Box>Using class component</Box>
 {this.state.data && <DataRenderer data={this.state.data} />}
 </Center>
 </NativeBaseProvider>
 );
 }
}

In this code, we told React to execute fetchCoffee on the first render (componentDidMount). This will fetch data from the API and store its response into the data state variable. In the end, we rendered the data array.

Run the code. This will be the output:

๐Ÿ‘ Class Component Coffee API

Some people might think that it is better to fetch data in the componentWillMount function instead, which is executed right before the component is mounted. There are two justifications why you shouldnโ€™t do it:

  • Itโ€™s deprecated as of React v17
  • When you use the Fetch API in componentWillMount(), React Native will render your data without waiting for the first render. This will cause a blank screen for the first time. For this reason, the time saved wonโ€™t be substantial

Conclusion

In this article, we explored a handful of common strategies to fetch data in React Native. At this moment, I would opt for using Apisauce and Hooks for my project. Not only are they an absolute breeze to use, but they are also robust. Consequently, this brings app security and efficiency to the table.

Thank you so much for reading! Happy coding!

LogRocket: Instantly identify and recreate issues in your React Native apps

๐Ÿ‘ Image

LogRocket's Galileo AI watches sessions for you and and surfaces the technical and usability issues holding back your React Native apps.

LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.

Start proactively monitoring your React Native apps โ€” try LogRocket for free.

๐Ÿ‘ Image
๐Ÿ‘ Image
๐Ÿ‘ Image

Stop guessing about your digital experience with LogRocket

Get started for free

Recent posts:

Debug Next.js apps with AI agents and next-browser

Learn how next-browser gives AI agents runtime context for debugging Next.js apps, including React props, hydration, PPR, forms, and performance.

๐Ÿ‘ Image
Emmanuel John
Jun 17, 2026 โ‹… 9 min read

Stop hardcoding LLM SDKs: Dynamic LLM routing with OpenRouter and Next.js

Build dynamic LLM routing in Next.js with OpenRouter, TanStack AI, task classification, model fallbacks, and cost-aware routing.

๐Ÿ‘ Image
Chizaram Ken
Jun 16, 2026 โ‹… 13 min read

What is TSRX?: What JSX would look like if it were designed today

TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension โ€” no new framework required.

๐Ÿ‘ Image
Ikeh Akinyemi
Jun 12, 2026 โ‹… 6 min read

How to add authentication to a React Native app with Better Auth

Learn how to build a full React Native auth system using Better Auth and Expo โ€” with email/password login, Google OAuth, session persistence, and protected routes.

๐Ÿ‘ Image
Chinwike Maduabuchi
Jun 9, 2026 โ‹… 13 min read
View all posts

Would you be interested in joining LogRocket's developer community?

Join LogRocketโ€™s Content Advisory Board. Youโ€™ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now