Mamun Labs Learn
JourneyGlossary
esc
  • Try “map”, “flexbox” or “state”.
Log in
Start learning
Phase 6 · 9 / 10Saving data on the phone
Phase 6React Native with Expo
10 topics · 6–8 wks
  1. 1Your first Expo app
  2. 2View, Text and Image
  3. 3Pressable and TextInput
  4. 4Styling and flexbox on mobile
  5. 5Lists with FlatList
  6. 6Safe areas and the keyboard
  7. 7Screens and navigation
  8. 8Tabs
  9. 9Saving data on the phone
  10. 10Calling an API
JourneyPhase 6Saving data on the phone
01 / 09Overview

Saving data on the phone

You'll learn to save data on the phone with AsyncStorage, so your habits are still there after the app closes.

Why it mattersA habit tracker that forgets every tick when you close it is useless. Every app that remembers settings or a list does this.
about 90 min·needs: useEffect, Promises and await, Lists with FlatList
02 / 09

Watch & read

Start with the required ones. The others are there when you need them.

Docs
Async Storage: usagereact-native-async-storage · official docs · 10 min · English
MMamun's noteShort and clear. Read "Storing data" and "Reading data", for both a string and an object. This is the version Expo installs today and links from its own docs. The site's newer version 3 adds named storages; the AsyncStorage.setItem and getItem you learn here still work there.
Video
React Native crash course 2026YouTube · Traversy Media · 13 min · English
MMamun's noteWatch 56:12–1:08:56. Brad installs AsyncStorage, writes small getMeals and addMeal functions that stringify and parse a list, hooks up a form, and loads the list when the screen opens. His code is TypeScript; skip the type parts and read the logic.
DocsOptional
Store datadocs.expo.dev · official docs · 5 min · English
MMamun's noteA one-page map of the ways to save data in an Expo app: AsyncStorage for small things, SecureStore for secrets, SQLite for a real database. Read it so you know which to reach for later.
VideoOptional
React Native full course for beginnersYouTube · freeCodeCamp · 9 min · English
MMamun's noteWatch 188:32–197:38 (3:08:32 to 3:17:38 in the video). He adds AsyncStorage to a to-do app, loads the list in one effect and saves it in another whenever the to-dos change. Very close to your habit tracker.
03 / 09

Explanation

State lives in the phone's memory only while the app is open. Close the app, and every ticked habit is gone. You need to write it down somewhere that stays.

Think of a notebook with labelled pages. You write on the page called "habits", and next time you open the notebook to the same page and read it back. AsyncStorage is that notebook, kept on the phone. Each page has a name (the key) and holds one string (the value).

import AsyncStorage from "@react-native-async-storage/async-storage";
await AsyncStorage.setItem("habits", JSON.stringify(habits)); // save
const saved = await AsyncStorage.getItem("habits"); // load: a string, or null
const habits = saved ? JSON.parse(saved) : [];
  • setItem(key, value) saves a string. Your habits are an array of objects, so first turn them into text with JSON.stringify.
  • getItem(key) reads it back as a string. JSON.parse turns the text into an array again. If nothing was ever saved under that key, you get null, so give a starting value.
  • Both are async, like fetch: they return a promise, so you await them.

In a screen you do two things with useEffect: load once when the screen opens ([]), and save whenever the habits change ([habits]). Install it with npx expo install @react-native-async-storage/async-storage; expo install picks the version that matches your Expo SDK. Snack adds it for you when you import it.

People often save the array without JSON.stringify. AsyncStorage only stores strings. Stringify on the way in, parse on the way out, every time. The other trap: the save effect also runs on the very first render, while habits is still [], and can write an empty list over your saved one before loading is done. Keep a loaded flag and only save after loading.

AsyncStorage is for small things: a list of habits, a setting, a name. It is not encrypted, so never keep passwords in it. For a lot of data that you search and sort, Expo has expo-sqlite, a real database on the phone.

When you read storage code, find the key string (it must be the same for saving and loading), then check for stringify before saving and parse after loading.

Words to recognise
AsyncStoragesetItemgetItemJSON.stringifyJSON.parse
04 / 09

Code tour

Click a line number with a ring to read the note for that line.

src/hooks/useSavedHabits.js5 notes
1import AsyncStorage from "@react-native-async-storage/async-storage";
2import { useEffect, useState } from "react";
export function useSavedHabits() {
Mentor note · line 3
Your own hook: any screen can call useSavedHabits() and get habits that survive closing the app.
4 const [habits, setHabits] = useState([]);
5 const [loaded, setLoaded] = useState(false);
6 useEffect(() => {
AsyncStorage.getItem("habits").then((saved) => {
if (saved) setHabits(JSON.parse(saved));
9 setLoaded(true);
10 });
11 }, []);
12 useEffect(() => {
if (loaded) AsyncStorage.setItem("habits", JSON.stringify(habits));
}, [habits, loaded]);
15 return [habits, setHabits];
16}
05 / 09

Practice

Short drills. Take your time and read the code before you answer.

DrillPredict1 / 2
1async function loadHabits() {
2 const saved = await AsyncStorage.getItem("habits");
3 console.log(saved);
4}
5
6// The app was just installed. Nothing has ever been saved.
7loadHabits();
What does the first load give?
DrillKeep the ticks after a reload2 / 2
Tapping a habit ticks it, but a reload forgets everything. Save the habits with AsyncStorage so the ticks come back. Use the Snack's reload button, or close Expo Go on your phone, to test.
1import AsyncStorage from "@react-native-async-storage/async-storage";
2import { useEffect, useState } from "react";
3import { FlatList, Pressable, StyleSheet, Text, View } from "react-native";
4
5const start = [
6 { id: "h1", name: "Drink water", done: false },

Runs in the browser. Choose “My Device” in Snack to try it on your phone with Expo Go.

Working whenTick two habits, reload the app, and the same two are still ticked.Add a "Reset" button that calls AsyncStorage.removeItem("habits") and sets the habits back to start.
Check each goal yourself, then mark it.
06 / 09

Quick check

3 questions. Each one explains itself after you answer.

  1. 1 / 3What kind of value does AsyncStorage keep under a key?
  2. 2 / 3Where should loading the saved habits go in a screen?
  3. 3 / 3You tick a habit, save with setItem, and close the app completely. What happens when you open it again?
07 / 09

Explain it back

Only you can see this. Log in to keep it.0 words
08 / 09

How confident are you with Saving data on the phone?

09 / 09

Done

You can now
Read code that saves and loads with AsyncStorage and say what is stored, under which key, and when.
Next: Calling an API Back to Phase 6
On this page
  1. 01Saving data on the phone
  2. 02Watch & read
  3. 03Explanation
  4. 04Code tour
  5. 05Practice
  6. 06Quick check
  7. 07Explain it back
  8. 08Confidence
  9. 09Done
Up next · 02 / 09Watch & read
Mamun Labs LearnFound a mistake on this page? Tell Mamun.
Mamun Labs Learn
JourneyGlossary
esc
  • Try “map”, “flexbox” or “state”.
Log in
Start learning
Log in to save your progress. Everything here works without an account.Log in to save progressLog in
Phase 6React Native with Expo
10 topics · 6–8 wks
  1. 1Your first Expo app
  2. 2View, Text and Image
  3. 3Pressable and TextInput
  4. 4Styling and flexbox on mobile
  5. 5Lists with FlatList
  6. 6Safe areas and the keyboard
  7. 7Screens and navigation
  8. 8Tabs
  9. 9Saving data on the phone
  10. 10Calling an API
JourneyPhase 6Saving data on the phone
01 / 09Overview

Saving data on the phone

You'll learn to save data on the phone with AsyncStorage, so your habits are still there after the app closes.

Why it mattersA habit tracker that forgets every tick when you close it is useless. Every app that remembers settings or a list does this.
about 90 min·needs: useEffect, Promises and await, Lists with FlatList
02 / 09

Watch & read

Start with the required ones. The others are there when you need them.

Docs
Async Storage: usagereact-native-async-storage · official docs · 10 min · English
MMamun's noteShort and clear. Read "Storing data" and "Reading data", for both a string and an object. This is the version Expo installs today and links from its own docs. The site's newer version 3 adds named storages; the AsyncStorage.setItem and getItem you learn here still work there.
Video
React Native crash course 2026YouTube · Traversy Media · 13 min · English
MMamun's noteWatch 56:12–1:08:56. Brad installs AsyncStorage, writes small getMeals and addMeal functions that stringify and parse a list, hooks up a form, and loads the list when the screen opens. His code is TypeScript; skip the type parts and read the logic.
DocsOptional
Store datadocs.expo.dev · official docs · 5 min · English
MMamun's noteA one-page map of the ways to save data in an Expo app: AsyncStorage for small things, SecureStore for secrets, SQLite for a real database. Read it so you know which to reach for later.
VideoOptional
React Native full course for beginnersYouTube · freeCodeCamp · 9 min · English
MMamun's noteWatch 188:32–197:38 (3:08:32 to 3:17:38 in the video). He adds AsyncStorage to a to-do app, loads the list in one effect and saves it in another whenever the to-dos change. Very close to your habit tracker.
03 / 09

Explanation

State lives in the phone's memory only while the app is open. Close the app, and every ticked habit is gone. You need to write it down somewhere that stays.

Think of a notebook with labelled pages. You write on the page called "habits", and next time you open the notebook to the same page and read it back. AsyncStorage is that notebook, kept on the phone. Each page has a name (the key) and holds one string (the value).

import AsyncStorage from "@react-native-async-storage/async-storage";
await AsyncStorage.setItem("habits", JSON.stringify(habits)); // save
const saved = await AsyncStorage.getItem("habits"); // load: a string, or null
const habits = saved ? JSON.parse(saved) : [];
  • setItem(key, value) saves a string. Your habits are an array of objects, so first turn them into text with JSON.stringify.
  • getItem(key) reads it back as a string. JSON.parse turns the text into an array again. If nothing was ever saved under that key, you get null, so give a starting value.
  • Both are async, like fetch: they return a promise, so you await them.

In a screen you do two things with useEffect: load once when the screen opens ([]), and save whenever the habits change ([habits]). Install it with npx expo install @react-native-async-storage/async-storage; expo install picks the version that matches your Expo SDK. Snack adds it for you when you import it.

People often save the array without JSON.stringify. AsyncStorage only stores strings. Stringify on the way in, parse on the way out, every time. The other trap: the save effect also runs on the very first render, while habits is still [], and can write an empty list over your saved one before loading is done. Keep a loaded flag and only save after loading.

AsyncStorage is for small things: a list of habits, a setting, a name. It is not encrypted, so never keep passwords in it. For a lot of data that you search and sort, Expo has expo-sqlite, a real database on the phone.

When you read storage code, find the key string (it must be the same for saving and loading), then check for stringify before saving and parse after loading.

Words to recognise
AsyncStoragesetItemgetItemJSON.stringifyJSON.parse
04 / 09

Code tour

Click a line number with a ring to read the note for that line.

src/hooks/useSavedHabits.js5 notes
1import AsyncStorage from "@react-native-async-storage/async-storage";
2import { useEffect, useState } from "react";
export function useSavedHabits() {
Mentor note · line 3
Your own hook: any screen can call useSavedHabits() and get habits that survive closing the app.
4 const [habits, setHabits] = useState([]);
5 const [loaded, setLoaded] = useState(false);
6 useEffect(() => {
AsyncStorage.getItem("habits").then((saved) => {
if (saved) setHabits(JSON.parse(saved));
9 setLoaded(true);
10 });
11 }, []);
12 useEffect(() => {
if (loaded) AsyncStorage.setItem("habits", JSON.stringify(habits));
}, [habits, loaded]);
15 return [habits, setHabits];
16}
05 / 09

Practice

Short drills. Take your time and read the code before you answer.

DrillPredict1 / 2
1async function loadHabits() {
2 const saved = await AsyncStorage.getItem("habits");
3 console.log(saved);
4}
5
6// The app was just installed. Nothing has ever been saved.
7loadHabits();
What does the first load give?
DrillKeep the ticks after a reload2 / 2
Tapping a habit ticks it, but a reload forgets everything. Save the habits with AsyncStorage so the ticks come back. Use the Snack's reload button, or close Expo Go on your phone, to test.
1import AsyncStorage from "@react-native-async-storage/async-storage";
2import { useEffect, useState } from "react";
3import { FlatList, Pressable, StyleSheet, Text, View } from "react-native";
4
5const start = [
6 { id: "h1", name: "Drink water", done: false },

Runs in the browser. Choose “My Device” in Snack to try it on your phone with Expo Go.

Working whenTick two habits, reload the app, and the same two are still ticked.Add a "Reset" button that calls AsyncStorage.removeItem("habits") and sets the habits back to start.
Check each goal yourself, then mark it.
06 / 09

Quick check

3 questions. Each one explains itself after you answer.

  1. 1 / 3What kind of value does AsyncStorage keep under a key?
  2. 2 / 3Where should loading the saved habits go in a screen?
  3. 3 / 3You tick a habit, save with setItem, and close the app completely. What happens when you open it again?
07 / 09

Explain it back

Only you can see this. Log in to keep it.0 words
08 / 09

How confident are you with Saving data on the phone?

09 / 09

Done

You can now
Read code that saves and loads with AsyncStorage and say what is stored, under which key, and when.
Next: Calling an API Back to Phase 6
On this page
  1. 01Saving data on the phone
  2. 02Watch & read
  3. 03Explanation
  4. 04Code tour
  5. 05Practice
  6. 06Quick check
  7. 07Explain it back
  8. 08Confidence
  9. 09Done
Up next · 02 / 09Watch & read

State lives in the phone's memory only while the app is open. Close the app, and every ticked habit is gone. You need to write it down somewhere that stays.

Think of a notebook with labelled pages. You write on the page called "habits", and next time you open the notebook to the same page and read it back. AsyncStorage is that notebook, kept on the phone. Each page has a name (the key) and holds one string (the value).

import AsyncStorage from "@react-native-async-storage/async-storage";
await AsyncStorage.setItem("habits", JSON.stringify(habits)); // save
const saved = await AsyncStorage.getItem("habits"); // load: a string, or null
const habits = saved ? JSON.parse(saved) : [];
  • setItem(key, value) saves a string. Your habits are an array of objects, so first turn them into text with JSON.stringify.
  • getItem(key) reads it back as a string. JSON.parse turns the text into an array again. If nothing was ever saved under that key, you get null, so give a starting value.
  • Both are async, like fetch: they return a promise, so you await them.

In a screen you do two things with useEffect: load once when the screen opens ([]), and save whenever the habits change ([habits]). Install it with npx expo install @react-native-async-storage/async-storage; expo install picks the version that matches your Expo SDK. Snack adds it for you when you import it.

People often save the array without JSON.stringify. AsyncStorage only stores strings. Stringify on the way in, parse on the way out, every time. The other trap: the save effect also runs on the very first render, while habits is still [], and can write an empty list over your saved one before loading is done. Keep a loaded flag and only save after loading.

AsyncStorage is for small things: a list of habits, a setting, a name. It is not encrypted, so never keep passwords in it. For a lot of data that you search and sort, Expo has expo-sqlite, a real database on the phone.

When you read storage code, find the key string (it must be the same for saving and loading), then check for stringify before saving and parse after loading.

Words to recognise
AsyncStoragesetItemgetItemJSON.stringifyJSON.parse

State lives in the phone's memory only while the app is open. Close the app, and every ticked habit is gone. You need to write it down somewhere that stays.

Think of a notebook with labelled pages. You write on the page called "habits", and next time you open the notebook to the same page and read it back. AsyncStorage is that notebook, kept on the phone. Each page has a name (the key) and holds one string (the value).

import AsyncStorage from "@react-native-async-storage/async-storage";
await AsyncStorage.setItem("habits", JSON.stringify(habits)); // save
const saved = await AsyncStorage.getItem("habits"); // load: a string, or null
const habits = saved ? JSON.parse(saved) : [];
  • setItem(key, value) saves a string. Your habits are an array of objects, so first turn them into text with JSON.stringify.
  • getItem(key) reads it back as a string. JSON.parse turns the text into an array again. If nothing was ever saved under that key, you get null, so give a starting value.
  • Both are async, like fetch: they return a promise, so you await them.

In a screen you do two things with useEffect: load once when the screen opens ([]), and save whenever the habits change ([habits]). Install it with npx expo install @react-native-async-storage/async-storage; expo install picks the version that matches your Expo SDK. Snack adds it for you when you import it.

People often save the array without JSON.stringify. AsyncStorage only stores strings. Stringify on the way in, parse on the way out, every time. The other trap: the save effect also runs on the very first render, while habits is still [], and can write an empty list over your saved one before loading is done. Keep a loaded flag and only save after loading.

AsyncStorage is for small things: a list of habits, a setting, a name. It is not encrypted, so never keep passwords in it. For a lot of data that you search and sort, Expo has expo-sqlite, a real database on the phone.

When you read storage code, find the key string (it must be the same for saving and loading), then check for stringify before saving and parse after loading.

Words to recognise
AsyncStoragesetItemgetItemJSON.stringifyJSON.parse