How to Fetch Data in React Native Using Axios

Step-by-Step Guide to Adding a Splash Screen in Your React Native Application

This article dives deep into using Axios within a React Native app, covering setup, basic usage, advanced configurations, error handling, and best practices to ensure you have all the tools needed to work with remote data efficiently.

Introduction

Fetching data from the internet is a staple in modern mobile applications. React Native developers often turn to Axios, a promise-based HTTP client, for this task due to its simplicity and robust features.

Axios is an HTTP client library that allows you to make requests to REST endpoints. Its promise-based nature makes it a great choice for asynchronous operations in JavaScript, offering a clean and readable syntax for handling responses and errors.

Why Axios Over Fetch?

While React Native's global fetch function is sufficient for basic HTTP requests, Axios provides a more powerful and flexible API for configuring requests, handling responses, and processing errors.

Features like automatic JSON data transformation, request and response interception, and timeout handling make Axios a robust solution for any React Native project.

Prerequisites

To demonstrate Axios in action, we’ll start by setting up a basic React Native app:

npx react-native init AxiosApp

For those who have an existing project, ensure it’s updated and ready for integration.

Pre-built Simple News Feed Screen For this example we will be using one of the WithFrame’s pre-built news feed components.

Installation

To install the package, run:

npm install axios

Or, if you are using yarn package manager:

yarn add axios

Making a Request

Let's start by fetching data from a placeholder API.

  1. Create a fetchPosts function:

In your project, create a file named ApiService.js. This will house our Axios calls.

Next, add a simple fetchPosts function to load article posts using axios package we installed earlier.

import axios from "axios";

export const fetchPosts = async () => {
  try {
    const response = await axios.get(
      "https://assets.withfra.me/api/posts.json"
    );
    return response.data;
  } catch (error) {
    console.error("Error fetching posts:", error);
    throw error;
  }
};
  1. Display Data in Your App:

Next, import fetchPosts in your component and call it when the component mounts, displaying the fetched data:

import {fetchPosts} from './ApiService.js';

export default function Example() {
  const [posts, setPosts] = useState(null);

  useEffect(() => {
    fetchPosts()
      .then(data => setPosts(data))
      .catch(() => {})
  }, []);

  return (
    ...
  )
}
  1. Add Loading Animation:

It's important for user experience to display the loading animation any time user has to wait for something to happen.

Pre-built Simple News Feed Component with Loading Spinner

In this case we will be using a native React Native spinner called ActivityIndicator.

export default function Example() {
  const [posts, setPosts] = useState(null);

  useEffect(() => {
    fetchPosts()
      .then(data => setPosts(data))
      .catch(() => {})
  }, []);

  // `useMemo` is optional, to only re-render the content when the `posts` are updated.
  const content = useMemo(() => {
    if (posts === null) {
      return (
        <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
          <ActivityIndicator size="large" color="#000" />
        </View>
      )
    }

    if (!posts?.length) {
      return (
        <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
          <Text>Could not find any posts</Text>
        </View>
      )
    }

    return (
      ...
    )
  }, [posts])
}
  1. Final result

Lastly, add the UI for article posts and render them in your app. The final component code should look something like this:

export default function Example() {
  const [posts, setPosts] = useState(null);

  useEffect(() => {
    fetchPosts()
      .then((data) => setPosts(data))
      .catch(() => {});
  }, []);

  // `useMemo` is optional, to only re-render the content when the `posts` are updated.
  const content = useMemo(() => {
    if (posts === null) {
      return (
        <View
          style={{ flex: 1, alignItems: "center", justifyContent: "center" }}
        >
          <ActivityIndicator size="large" color="#000" />
        </View>
      );
    }

    if (!posts?.length) {
      return (
        <View
          style={{ flex: 1, alignItems: "center", justifyContent: "center" }}
        >
          <Text>Could not find any posts</Text>
        </View>
      );
    }

    return posts.map(({ img, title, author, authorImg, tag, date }, index) => {
      return (
        <TouchableOpacity
          key={index}
          onPress={() => {
            // handle onPress
          }}
        >
          <View style={styles.card}>
            <Image
              alt=""
              resizeMode="cover"
              source={{ uri: img }}
              style={styles.cardImg}
            />

            <View style={styles.cardBody}>
              <Text style={styles.cardTag}>{tag}</Text>

              <Text style={styles.cardTitle}>{title}</Text>

              <View style={styles.cardRow}>
                <View style={styles.cardRowItem}>
                  <Image
                    alt=""
                    source={{ uri: authorImg }}
                    style={styles.cardRowItemImg}
                  />

                  <Text style={styles.cardRowItemText}>{author}</Text>
                </View>

                <Text style={styles.cardRowDivider}>·</Text>

                <View style={styles.cardRowItem}>
                  <Text style={styles.cardRowItemText}>{date}</Text>
                </View>
              </View>
            </View>
          </View>
        </TouchableOpacity>
      );
    });
  }, [posts]);

  return (
    <SafeAreaView style={{ backgroundColor: "#fff", flex: 1 }}>
      <ScrollView contentContainerStyle={styles.container}>
        <Text style={styles.title}>News Feed</Text>

        {content}
      </ScrollView>
    </SafeAreaView>
  );
}

Advanced Axios Features

Axios shines with its advanced features that cater to more complex scenarios.

Setting Global Configurations

For projects requiring multiple requests to the same server, setting a global base URL and default headers can streamline your code.

axios.defaults.baseURL = "https://assets.withfra.me/api";
axios.defaults.headers.common["Authorization"] = "Bearer YOUR_TOKEN";
axios.defaults.headers.post["Content-Type"] = "application/json";

Using Interceptors

Interceptors allow you to run your code or modify requests and responses before they are handled by then or catch.

// Add a request interceptor
axios.interceptors.request.use((request) => {
  console.log("Starting Request", request);
  return request;
});

// Add a response interceptor
axios.interceptors.response.use((response) => {
  console.log("Response:", response);
  return response;
});

Handling Timeouts

To prevent requests from hanging indefinitely, you can specify a timeout.

axios
  .get("https://assets.withfra.me/api/posts.json", { timeout: 5000 })
  .then((response) => console.log(response.data))
  .catch((error) => console.error("Timeout error:", error));

Making POST Requests

Submitting data to a server is straightforward with Axios's post method.

const newPost = {
  userId: 1,
  title: "Axios with React Native",
  body: "Using Axios for HTTP requests is simple and efficient.",
};

axios
  .post("/posts", newPost)
  .then((response) => console.log(response.data))
  .catch((error) => console.error("Error creating post:", error));

Error Handling

Robust error handling ensures a smooth user experience, even when things go wrong. Axios errors can be caught using .catch():

axios
  .get("/nonexistent-endpoint")
  .then((response) => console.log(response))
  .catch((error) => {
    if (error.response) {
      // The request was made and the server responded with a status code
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.headers);
    } else if (error.request) {
      // The request was made but no response was received
      console.log(error.request);
    } else {
      // Something happened in setting up the request
      console.log("Error", error.message);
    }
  });

Best Practices

  • Use async/await: For cleaner syntax and better error handling, prefer using async/await over traditional promise syntax.
  • Centralize API Calls: Keep your API calls in separate service files to maintain cleaner components and facilitate easier testing.
  • Handle Loading States: Use state hooks to manage loading states in your UI, providing feedback to users during data fetching.
  • Secure Your API: If your API requires authentication, ensure secure storage of tokens and implement proper session management.

Conclusion

Axios is a powerful and versatile HTTP client that makes it easier to consume REST APIs in React Native apps.

By understanding and leveraging Axios' full suite of features, developers can efficiently handle HTTP requests, streamline error handling, and enhance the overall user experience of their applications.

Remember, while Axios simplifies the process of working with asynchronous data, effective error handling and state management are key to building robust and user-friendly mobile applications.