Codecademy Logo

Working with Data

Related learning

  • Build mobile apps with TypeScript and React, using Expo and React Native
    • Intermediate.
      12 hours

Fetching Data in React Native

React Native uses the Fetch API for network requests, providing a Promise-based interface that works consistently across iOS and Android platforms. The API includes built-in support for standard HTTP methods, JSON parsing, and request configuration options.

// Basic GET request
const response = await fetch('https://api.example.com/data');
if (!response.ok) throw new Error('Request failed');
const data: any = await response.json();
// POST request with configuration
const postResponse = await fetch('https://api.example.com/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'John', email: '[email protected]' })
});
const user: any = await postResponse.json();

Transforming API Data for React Native Components

API responses in React Native frequently contain extra metadata, inconsistent field names, or structures not directly compatible with components like <FlatList>. A transformation step reshapes this data, optimizing it for fast rendering and features such as search, by producing a predictable format expected by the component.

const transformForFlatList = (data: { Results: { Make_ID: number; Make_Name: string }[] }) =>
data.Results.map(item => ({
id: item.Make_ID,
title: item.Make_Name
.toLowerCase()
.split(' ')
.map(word => word[0].toUpperCase() + word.slice(1))
.join(' '),
searchableText: item.Make_Name.toLowerCase(),
}));
// Example usage:
const apiResponse = {
Count: 10426,
Message: "Response returned successfully",
Results: [
{ Make_ID: 440, Make_Name: "ASTON MARTIN" },
{ Make_ID: 441, Make_Name: "TESLA" }
]
};
const flatListData = transformForFlatList(apiResponse);

AsyncStorage Usage

AsyncStorage offers an asynchronous key-value storage solution for React Native, suitable for user preferences, tokens, or small data on both iOS and Android. All values are stored as strings, so objects must be serialized before storage and parsed after retrieval.

import AsyncStorage from '@react-native-async-storage/async-storage';
// Saving a string value
await AsyncStorage.setItem('@username', 'john_doe');
// Saving an object
const user = { id: 123, name: 'John Doe', theme: 'dark' };
await AsyncStorage.setItem('@user_data', JSON.stringify(user));
// Retrieving values
const username = await AsyncStorage.getItem('@username');
const userDataString = await AsyncStorage.getItem('@user_data');
const userData = userDataString
? JSON.parse(userDataString) as { id: number; name: string; theme: string }
: null;

Data Persistence in React Native

React Native includes several data persistence options. For basic key-value storage, AsyncStorage provides asynchronous, unencrypted local storage for small, non-sensitive data. For structured data requirements, solutions such as expo-sqlite support relational databases. Encrypted storage of sensitive information can be achieved with modules like expo-secure-store.

Selection of a storage solution depends on data size, sensitivity, retrieval speed, and security requirements.

Caching Data in React Native

Caching in React Native refers to storing data or resources locally on the device to speed up access and reduce unnecessary network requests. This improves app performance, makes frequently used data available offline, and results in a smoother user experience.

AsyncStorage provides a way to cache frequently accessed data by saving it on the device. Caching strategies should be chosen based on the type of data, the need for persistence, and the desired balance between speed, storage, and freshness of content.

import AsyncStorage from '@react-native-async-storage/async-storage';
// Save data with expiration (default: 30 minutes)
const createCache = async (key: string, data: any, minutes = 30) => {
const cacheEntry = {
data,
expires: Date.now() + minutes * 60 * 1000,
};
await AsyncStorage.setItem(`cache:${key}`, JSON.stringify(cacheEntry));
};
// Retrieve cached data if not expired; otherwise, remove the cache and return null
const getCache = async (key: string): Promise<any | null> => {
const cached = await AsyncStorage.getItem(`cache:${key}`);
if (!cached) return null;
const entry = JSON.parse(cached);
if (Date.now() > entry.expires) {
await AsyncStorage.removeItem(`cache:${key}`);
return null;
}
return entry.data;
};

Offline-first Pattern Development

The offline-first pattern describes an approach where data is loaded from local storage first, providing instant results before attempting to fetch updates from the network. In React Native, AsyncStorage is often used to cache data locally, ensuring apps remain responsive and functional even without network connectivity.

import AsyncStorage from '@react-native-async-storage/async-storage';
const loadDataOfflineFirst = async (setData: (data: any) => void) => {
// Load cached data immediately
const localData = await AsyncStorage.getItem('cached_data');
if (localData) setData(JSON.parse(localData));
// Fetch fresh data and update cache in background
try {
const response = await fetch('/api/data');
const freshData = await response.json();
await AsyncStorage.setItem('cached_data', JSON.stringify(freshData));
setData(freshData);
} catch {
// Continue using cached data if fetch fails
console.log('Using cached data due to network error');
}
};

User Feedback During Network Operations

Providing user feedback during network operations is essential in mobile apps, as connectivity can be slow or unreliable, and operations may take longer than expected. Clear indicators such as loading spinners, error messages, or status bars help users understand what is happening and prevent confusion or frustration.

In React Native, common patterns for user feedback involve managing loading and error states, displaying activity indicators, and visually signaling whether data is loaded from the network or cache.

import { useState } from 'react';
import { ActivityIndicator, Text, View } from 'react-native';
// State management for feedback
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// In render
{loading && <ActivityIndicator size="large" color="#007AFF" />}
{error && <Text>Failed to load data. Please try again.</Text>}
// Status indicator color for network vs. cache
const statusColor = dataSource === 'network' ? '#34C759' : '#FF9500';
<View style={[styles.indicator, { backgroundColor: statusColor }]} />

Pulling to Refresh in React Native

Pull-to-refresh is a standard interaction in mobile apps, enabling users to manually update data by pulling down on a scrollable list. In React Native, the <RefreshControl> component provides this behavior for lists like <FlatList> and <ScrollView>, displaying a loading indicator and triggering a refresh function when activated.

<RefreshControl> gives users direct control over data freshness and improves the app experience when automatic updates are insufficient or network conditions are variable.

import { FlatList, RefreshControl } from 'react-native';
// State for refresh control
const [refreshing, setRefreshing] = useState(false);
const [data, setData] = useState<any[]>([]);
// Refresh handler
const handleRefresh = async () => {
setRefreshing(true);
try {
const freshData = await fetchDataFromAPI();
setData(freshData);
} finally {
setRefreshing(false);
}
};
// In the component render
<FlatList
data={data}
renderItem={renderItem}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
colors={['#007AFF']}
tintColor="#007AFF"
/>
}
/>

Mobile Data Lifecycle

Mobile apps must address data staleness caused by app lifecycle events, such as transitioning between background and foreground. Unlike web applications, which reload on each visit, mobile apps often pause data fetching when moved to the background and resume with potentially outdated information. As a result, effective strategies are needed to refresh or validate data when the app returns to the foreground, ensuring users always see up-to-date content.

Learn more on Codecademy

  • Build mobile apps with TypeScript and React, using Expo and React Native
    • Intermediate.
      12 hours