![]()
In the previous article, our application learned how to "talk" to the Server via API to fetch data. However, a major issue arises:
Every time users close the app and reopen it, everything goes back to square one! Users have to log in again from scratch, the application forgets whether they are using Dark Mode or Light Mode, and the articles they have read are not saved.
If the API is the door connecting to the outside world, then Local Storage is the secret "notebook" hidden inside the phone. In this lesson, we will learn how to write in that notebook so your application has an excellent "memory"!
1. AsyncStorage: The "golden" standard of React Native
If you have ever done Web development, you definitely know about localStorage. In the React Native world, its cousin is named AsyncStorage.

AsyncStorage is a data storage system in the form of Key - Value. All data you save here is converted into text strings (String) and will exist permanently on the phone until the user uninstalls the app or manually clears the app data.
Installing AsyncStorage in Expo
Open your project's Terminal and run the following command:
npx expo install @react-native-async-storage/async-storage
How to work with AsyncStorage
Because the phone's storage system needs time to read/write to the hard drive, all operations with AsyncStorage are Asynchronous. Therefore, you always have to use async / await when working with it.
Let's see how the application saves the user's display name:
import AsyncStorage from '@react-native-async-storage/async-storage'
// 1. SAVE DATA (Put in the closet)
const saveUsername = async (name) => {
try {
await AsyncStorage.setItem('@username_key', name)
console.log('Successfully saved name!')
} catch (e) {
console.error('Error saving data:', e)
}
}
// 2. GET DATA (Open closet and take out)
const getUsername = async () => {
try {
const value = await AsyncStorage.getItem('@username_key')
if (value !== null) {
console.log('Welcome back:', value)
}
} catch (e) {
console.error('Error reading data:', e)
}
}
// 3. REMOVE DATA (Logout)
const removeUsername = async () => {
try {
await AsyncStorage.removeItem('@username_key')
console.log('Successfully removed data!')
} catch (e) {
console.error('Error removing data:', e)
}
}
Note: AsyncStorage can ONLY store strings. If you want to store an Object containing user information (e.g.:
{ id: 1, role: 'admin' }), you must useJSON.stringify()before saving, andJSON.parse()after retrieving.
2. Absolute safety with Expo SecureStore
AsyncStorage is great for storing UI configurations (Theme, Language) or non-critical data.
But WARNING: You absolutely MUST NOT use AsyncStorage to store passwords, credit card information, or login Tokens (JWT)! Data in AsyncStorage is plain-text, hackers can easily plug a cable into the phone and extract all this data.
For sensitive information, the Expo ecosystem provides us with an "armored safe" named SecureStore. It encrypts your data using the highest-level security algorithms of the operating system (Keychain on iOS and Keystore on Android).

Installation:
npx expo install expo-secure-store
Usage (Almost identical to AsyncStorage but 100 times safer):
import * as SecureStore from 'expo-secure-store'
// Save login Token securely
async function saveToken(token) {
await SecureStore.setItemAsync('user_token', token)
}
// Retrieve Token to attach to API Request
async function getToken() {
let result = await SecureStore.getItemAsync('user_token')
if (result) {
console.log('Your Password/Token is securely protected!')
}
}
3. MMKV: The performance "monster" (For large projects)
As your application grows, you might realize AsyncStorage operates a bit slowly when having to save/read a list of thousands of viewed products.
The React Native community is currently going crazy over a new storage solution named react-native-mmkv (developed by Tencent).

Why is MMKV highly sought after?
- 30 times faster than AsyncStorage.
- It operates Synchronously! Meaning you don't need to write the tiring
async/awaitanymore. The UI will display data immediately without any delay (Loading).
Note for Expo users: To use MMKV, you cannot use the standard Expo Go app, but must create a Development Build because it contains Native C++ source code that deeply intervenes in the memory. This is advanced knowledge that we will explore in the final stages of the series!
4. Practice: Onboarding Feature
Let's apply AsyncStorage right away to a very realistic scenario: When users just downloaded the app, you want to show the Onboarding screen. But from the 2nd time opening the app onwards, you want them to go straight to the Home Screen.
Let's use the useEffect Hook combined with AsyncStorage:
import React, { useEffect, useState } from 'react'
import { View, Text, ActivityIndicator } from 'react-native'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { useRouter } from 'expo-router'
export default function RootApp() {
const [isFirstLaunch, setIsFirstLaunch] = useState(null)
const router = useRouter()
useEffect(() => {
async function checkFirstLaunch() {
// Check if the 'alreadyLaunched' flag exists
const hasLaunched = await AsyncStorage.getItem('alreadyLaunched')
if (hasLaunched === null) {
// Doesn't exist -> First app launch
await AsyncStorage.setItem('alreadyLaunched', 'true')
setIsFirstLaunch(true)
} else {
// Exists -> Not the first time
setIsFirstLaunch(false)
}
}
checkFirstLaunch()
}, [])
// Checking data in hard drive, showing spinner
if (isFirstLaunch === null) {
return <ActivityIndicator size="large" style={{ flex: 1 }} />
}
// Navigation based on result
if (isFirstLaunch) {
// If first time, router.replace() to Onboarding screen
return <Text>Welcome newcomer! Redirecting to Onboarding...</Text>
} else {
// Not first time, go straight to Home Screen
return <Text>Welcome back! Navigating to Home Screen...</Text>
}
}
Conclusion: Local data is also very important
The memory notebook in React Native has 3 distinct compartments:
- AsyncStorage: Used for normal data, app configuration. (Easiest to install, most commonly used).
- SecureStore: The security safe. Only used for Passwords, JWT Tokens, payment data.
- MMKV: The jet engine. Used when you need massive data retrieval speeds in the blink of an eye.
Now, your application has the ability to remember and call APIs. But what if you fetch User data on the Profile page, and want to use that data again on the Settings page? Passing data back and forth between dozens of screens will create an extremely tangled mess (called Prop Drilling).
It's time we explore centralized state management solutions, see you in the next article!