Skip to main content

Handling Networking and APIs

1. Using Fetch API

Property Description Example
fetch() Method to make HTTP requests fetch('https://api.example.com/data')
method HTTP method (GET, POST, PUT, DELETE) { method: 'POST' }
headers Request headers { 'Content-Type': 'application/json' }
body Request body (for POST/PUT) JSON.stringify({ name: 'John' })

Example: Fetch GET request

fetch('https://jsonplaceholder.typicode.com/posts/1')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

Example: Fetch POST request

fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'My Post',
    body: 'This is the content'
  })
})
.then(response => response.json())
.then(data => console.log(data));
Note: React Native's fetch API is based on the web standard, but does not support all features like cookies or credentials by default. For more advanced networking needs, consider using libraries like axios.

2. Handling Request Headers

Header Description Usage
Authorization Used to provide credentials for authentication headers: { 'Authorization': 'Bearer token123' }
Content-Type Indicates the media type of the resource headers: { 'Content-Type': 'application/json' }
Accept Specifies the media types that are acceptable for the response headers: { 'Accept': 'application/json' }
User-Agent Identifies the client making the request headers: { 'User-Agent': 'ReactNativeApp/1.0' }
Cache-Control Directs caching mechanisms for the request/response headers: { 'Cache-Control': 'no-cache' }

Example: Setting Custom Headers in Fetch

fetch('https://api.example.com/data', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer token123',
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'User-Agent': 'ReactNativeApp/1.0'
  }
})
.then(response => response.json())
.then(data => console.log(data));

Example: Sending Headers with POST Request

const postData = {
  title: 'My Post',
  content: 'This is the content'
};

fetch('https://api.example.com/posts', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer token123',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(postData)
})
.then(response => response.json())
.then(data => console.log('Post created:', data));

3. Managing API Responses

Property Description Example
status HTTP status code of the response 200, 404
statusText Readable status message "OK", "Not Found"
headers Response headers object {"content-type": "application/json"}
ok Boolean indicating if status is in 2xx range true, false

Example: Handling API Response

const response = await fetch('https://api.example.com/data');
if (response.ok) {
  const data = await response.json();
  console.log(data);
} else {
  console.error('Failed to fetch:', response.status, response.statusText);
}
Note: Always check response.ok before parsing JSON to avoid runtime errors from invalid responses.

Key Points

  • status and statusText provide HTTP status information.
  • headers can be used to read response metadata like content type.
  • ok is a convenient boolean to check for success status codes (2xx).
  • Always handle error cases when fetching data from external APIs.

4. Implementing Error Handling

Example: Basic Network Error Handling

import React, { useState } from 'react';

const ApiComponent = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const fetchData = async () => {
    setLoading(true);
    setError(null);
    try {
      const response = await fetch('https://api.example.com/data');
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      const result = await response.json();
      setData(result);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div>
      {loading && <p>Loading...</p>}
      {error && <p>Error: {error}</p>}
      {data && <p>Data: {JSON.stringify(data)}</p>}
    </div>
  );
};

export default ApiComponent;
Error Type Description Handling Strategy
Network Error Connection issues, timeouts, or offline state Retry logic with exponential backoff, user notification
HTTP Status Error Server returns 4xx or 5xx status codes Parse error code, show user-friendly message
Parse Error Invalid JSON or data format Validate response structure, fallback to defaults
Note: Always handle network errors gracefully to prevent app crashes and provide a better user experience.

Example: Retry Logic with Exponential Backoff

const fetchWithRetry = async (url, retries = 3, delay = 1000) => {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    if (retries > 0) {
      console.log(`Retrying... ${retries} attempts left`);
      await new Promise(resolve => setTimeout(resolve, delay));
      return fetchWithRetry(url, retries - 1, delay * 2);
    } else {
      throw new Error("Max retries exceeded");
    }
  }
};

// Usage
fetchWithRetry('https://api.example.com/data')
  .then(data => console.log(data))
  .catch(err => console.error("Failed after retries:", err));

Error Handling Best Practices

  • Implement centralized error logging using tools like Sentry or Bugsnag
  • Provide user-friendly messages instead of raw error codes
  • Use retry mechanisms for transient network issues
  • Gracefully degrade UI when API calls fail

5. Using Abort Controller

Feature Description Usage
AbortController API to signal cancellation of asynchronous operations const controller = new AbortController(); const signal = controller.signal;
abortSignal Signal used to cancel fetch requests or other async tasks fetch('/api/data', { signal });
abort() Method to trigger cancellation of the operation controller.abort();

Example: Canceling a Fetch Request

const controller = new AbortController();
const signal = controller.signal;

fetch('/api/data', { signal })
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(err => {
    if (err.name === 'AbortError') {
      console.log('Fetch was aborted');
    } else {
      console.error('Fetch error:', err);
    }
  });

// Cancel the request after 2 seconds
setTimeout(() => {
  controller.abort();
}, 2000);
Note: The AbortController is part of the Web API and supported in React Native environments.

6. Handling Network Errors

Error Type Description Handling Strategy Example
Network Error Occurs when the device cannot connect to the network or server. Use try-catch blocks and display user-friendly messages.
try {
  const response = await fetch('https://api.example.com/data');
  if (!response.ok) throw new Error('Network error');
} catch (error) {
  console.error('Network error:', error.message);
}
Timeout Error Request exceeds the set timeout limit. Implement retry logic or show timeout-specific UI.
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);

try {
  const response = await fetch('https://api.example.com/data', {
    signal: controller.signal
  });
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('Request timed out');
  }
}
HTTP Error (4xx/5xx) Server returns an error status code (e.g., 404, 500). Parse status codes and provide actionable feedback.
const response = await fetch('https://api.example.com/data');
if (response.status === 404) {
  alert('Resource not found');
} else if (response.status >= 500) {
  alert('Server error, please try again later');
}

Example: Error Boundary in React Native

import React from 'react';
import { View, Text } from 'react-native';

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    console.error('Caught an error:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return (
        <View>
          <Text>Something went wrong.</Text>
        </View>
      );
    }

    return this.props.children;
  }
}

export default ErrorBoundary;
Note: Implementing error boundaries helps in gracefully handling runtime errors in React Native components.

7. Implementing Request Timeouts

Property Description Default Value Notes
timeout Timeout in milliseconds for the request 5000 Used in fetch and XMLHttpRequest

Example: Setting Timeout with Fetch

const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);

fetch('https://api.example.com/data', {
  signal: controller.signal
})
.then(response => response.json())
.then(data => console.log(data))
.catch(err => {
  if (err.name === 'AbortError') {
    console.error('Request timed out');
  } else {
    console.error('Fetch error:', err);
  }
});
Note: The timeout property is not a native option in the fetch API, but can be implemented using AbortController.
Warning: When using AbortController, ensure that the timeout is cleared if the request completes before the timeout to prevent unnecessary aborts.

8. Using FormData

Property Description Usage
new FormData() Creates a new FormData object const formData = new FormData();
formData.append() Adds a new field to the FormData object formData.append('key', 'value');
formData.append() Adds a file to the FormData object formData.append('file', fileBlob, 'filename.jpg');
formData.get() Retrieves the first value of a field const value = formData.get('key');
formData.getAll() Retrieves all values of a field const values = formData.getAll('key');
formData.delete() Deletes a field from FormData formData.delete('key');
formData.has() Checks if a field exists const exists = formData.has('key');
formData.entries() Returns an iterator of all key-value pairs for (const [key, value] of formData.entries()) { ... }

Example: Sending FormData with fetch

const formData = new FormData();
formData.append('name', 'John Doe');
formData.append('avatar', fileBlob, 'avatar.jpg');

fetch('https://api.example.com/upload', {
  method: 'POST',
  body: formData
})
.then(response => response.json())
.then(data => console.log(data));
Note: FormData is not supported natively in React Native's fetch implementation. You may need to use a library like react-native-fetch-blob or axios for better FormData support.

9. Implementing Retry Logic

Example: Basic Retry with Exponential Backoff

const retryFetch = async (url, options = {}, maxRetries = 3) => {
  let lastError;
  
  for (let i = 0; i <= maxRetries; i++) {
    try {
      const response = await fetch(url, options);
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      return response.json();
    } catch (error) {
      lastError = error;
      if (i === maxRetries) break;
      
      const delay = Math.pow(2, i) * 1000; // Exponential backoff
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
  
  throw lastError;
};

// Usage
retryFetch('https://api.example.com/data')
  .then(data => console.log(data))
  .catch(error => console.error('Failed after retries:', error));
Option Values Description
maxRetries 3 Maximum number of retry attempts
backoffStrategy 'exponential' Delay strategy between retries
delayBase 1000 Base delay in milliseconds (multiplied by exponential factor)
Note: This example uses exponential backoff to avoid overwhelming the server with rapid retries.
Warning: Be cautious with retry logic in mobile apps as it can lead to increased data usage and battery drain.

10. Handling Offline Scenarios

Example: Detecting Network Status

import { NetInfo } from &#x27;react-native&#x27;;

NetInfo.fetch().then(state => {
  console.log("Connection type", state.type);
  console.log("Is connected", state.isConnected);
});
Property Description Values
isConnected Indicates if the device is connected to a network true / false
type Network type (e.g., WiFi, cellular) "none", "wifi", "cellular"
isInternetReachable Checks if the device can reach the internet true / false
Note: For newer versions of React Native, use NetInfo from @react-native-community/netinfo package.

Example: Using NetInfo with useEffect

import React, { useEffect, useState } from &#x27;react&#x27;;
import NetInfo from &#x27;@react-native-community/netinfo&#x27;;

const NetworkStatus = () => {
  const [isConnected, setIsConnected] = useState(false);

  useEffect(() => {
    const unsubscribe = NetInfo.addEventListener(state => {
      setIsConnected(state.isConnected);
    });

    return () => unsubscribe();
  }, []);

  return (
    <View>
      <Text>{isConnected ? "Online" : "Offline"}</Text>
    </View>
  );
};

Best Practices for Offline Handling

  • Always check network status before making API calls
  • Implement retry logic with exponential backoff for failed requests
  • Cache data locally using libraries like AsyncStorage or SQLite
  • Provide user feedback when the app is offline

11. Using WebSocket Connections

Property Description Example
WebSocket Native WebSocket API for real-time communication new WebSocket('ws://localhost:8080')
url WebSocket server URL 'wss://echo.websocket.org'
readyState Current state of the connection (0-3) WebSocket.CONNECTING

Example: Basic WebSocket Connection

import { WebSocket } from 'react-native'

Example: Sending and Receiving Messages

const ws = new WebSocket('ws://localhost:8080');

ws.onopen = () => {
  console.log('Connected');
  ws.send('Hello Server');
};

ws.onmessage = (event) => {
  console.log('Received:', event.data);
};

ws.onclose = () => {
  console.log('Disconnected');
};
Note: React Native's WebSocket implementation is based on the Web API but may differ in behavior from browser implementations.

12. Using Axios Library

Example: Basic GET Request

import axios from 'axios';

const fetchData = async () => {
  try {
    const response = await axios.get('https://api.example.com/data');
    console.log(response.data);
  } catch (error) {
    console.error('Error fetching data:', error);
  }
};

fetchData();
Property Description Default
url The URL to request data from None
method The HTTP method to use (GET, POST, PUT, DELETE) GET
headers HTTP headers to send with the request None
data Data to send in the request body (for POST/PUT) None
Note: Axios automatically handles JSON parsing and can be used in both React Native and web environments.

Example: POST Request with Data

import axios from 'axios';

const postData = async () => {
  try {
    const response = await axios.post('https://api.example.com/users', {
      name: 'John Doe',
      email: 'john@example.com'
    });
    console.log('User created:', response.data);
  } catch (error) {
    console.error('Error creating user:', error);
  }
};

postData();

Was this article helpful?