AsyncStorage — qurilmada ma'lumot saqlash

~12 daq · React Native · Ma'lumot va API

Muammodan boshlaylik

Foydalanuvchi:

  • Qorong'i mavzuni tanladi — ilovani qayta ochganda yorug' bo'lib qoldi
  • Onboarding ni ko'rdi — har safar qaytadan ko'rsatilmoqda
  • 24-darsdagi kontaktlarni kiritdi — ilova yopilganda hammasi yo'qoldi

Vebda localStorage bor. React Native da uning o'rni — AsyncStorage: qurilmada kalit-qiymat ko'rinishida doimiy saqlash.


O'rnatish

npx expo install @react-native-async-storage/async-storage

Asosiy amallar

import AsyncStorage from '@react-native-async-storage/async-storage';

// Saqlash — faqat string
await AsyncStorage.setItem('mavzu', 'qorongi');

// O'qish — yo'q bo'lsa null
const mavzu = await AsyncStorage.getItem('mavzu');   // 'qorongi' | null

// O'chirish
await AsyncStorage.removeItem('mavzu');

// Barcha kalitlar
const kalitlar = await AsyncStorage.getAllKeys();

// Hammasini tozalash (ehtiyot bo'ling!)
await AsyncStorage.clear();

localStorage dan ikki farq:

  1. Asinxron — await kerak (diskka yozish vaqt oladi va UI ni bloklamasligi kerak)
  2. Faqat string — ob'ektlar uchun JSON

Ob'ektlar

type Kontakt = { id: string; ism: string; telefon: string };

async function kontaktlarniSaqla(k: Kontakt[]) {
  await AsyncStorage.setItem('kontaktlar', JSON.stringify(k));
}

async function kontaktlarniOqi(): Promise<Kontakt[]> {
  const json = await AsyncStorage.getItem('kontaktlar');
  if (!json) return [];
  try {
    return JSON.parse(json) as Kontakt[];
  } catch {
    return [];       // buzilgan ma'lumot — ilova yiqilmasin
  }
}

Tiplangan yordamchi

// lib/xotira.ts
import AsyncStorage from '@react-native-async-storage/async-storage';

export const xotira = {
  async get<T>(kalit: string, standart: T): Promise<T> {
    try {
      const v = await AsyncStorage.getItem(kalit);
      return v === null ? standart : (JSON.parse(v) as T);
    } catch {
      return standart;
    }
  },
  async set<T>(kalit: string, qiymat: T) {
    await AsyncStorage.setItem(kalit, JSON.stringify(qiymat));
  },
  remove: (kalit: string) => AsyncStorage.removeItem(kalit),
};
const korildi = await xotira.get('onboarding_korildi', false);
await xotira.set('onboarding_korildi', true);

Onboarding — faqat bir marta

// app/_layout.tsx
const [tayyor, setTayyor] = useState(false);
const [onboardingKerak, setOnboardingKerak] = useState(false);

useEffect(() => {
  xotira.get('onboarding_korildi', false).then((korildi) => {
    setOnboardingKerak(!korildi);
    setTayyor(true);
  });
}, []);

if (!tayyor) return null;    // splash ko'rinib turadi

return (
  <Stack>
    <Stack.Protected guard={onboardingKerak}>
      <Stack.Screen name="onboarding" options={{ headerShown: false }} />
    </Stack.Protected>
    <Stack.Protected guard={!onboardingKerak}>
      <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
    </Stack.Protected>
  </Stack>
);

Onboarding oxirida:

await xotira.set('onboarding_korildi', true);
setOnboardingKerak(false);    // context yoki store orqali

Kontaktlarni saqlash — Zustand persist bilan

24-darsdagi ilovani saqlanadigan qilish. Qo'lda useEffect + AsyncStorage o'rniga — 33-darsdagi persist:

// stores/kontaktlar.ts
export const useKontaktlar = create<KontaktlarHolati>()(
  persist(
    (set) => ({
      kontaktlar: [],
      qosh: (k) => set((s) => ({ kontaktlar: [...s.kontaktlar, { ...k, id: String(Date.now()) }] })),
      ochir: (id) => set((s) => ({ kontaktlar: s.kontaktlar.filter((k) => k.id !== id) })),
    }),
    { name: 'kontaktlar', storage: createJSONStorage(() => AsyncStorage) }
  )
);

Ilova ochilganda Zustand ma'lumotni avtomatik o'qiydi ("hydration"), har o'zgarishda — saqlaydi.

Hydration tugadimi?

Ilova ochilgan birinchi lahzada store hali bo'sh — AsyncStorage asinxron o'qiladi. "Kontakt yo'q" ekrani bir lahza ko'rinib, keyin ro'yxat paydo bo'lishi mumkin:

const tayyor = useKontaktlar.persist.hasHydrated();
// yoki
const [tayyor, setTayyor] = useState(useKontaktlar.persist.hasHydrated());
useEffect(() => useKontaktlar.persist.onFinishHydration(() => setTayyor(true)), []);

Cheklovlar — qachon AsyncStorage EMAS

Holat Muammo Yechim
Token, parol, maxfiy kalit Shifrlanmagan — root qilingan qurilmada o'qiladi expo-secure-store (35-dars)
Katta ma'lumot (minglab yozuv) Butun qiymat har safar o'qiladi/yoziladi; Android da hajm chegarasi bor expo-sqlite
Qidiruv, filtr, saralash Kalit-qiymat — so'rovlar yo'q expo-sqlite
Fayllar, rasmlar String sifatida — juda sekin expo-file-system
Tez-tez o'qiladigan kichik sozlamalar Asinxron — har safar await react-native-mmkv (sinxron, juda tez)

AsyncStorage — kichik, maxfiy bo'lmagan ma'lumot uchun: sozlamalar, bayroqlar, kichik keshlar, qoralamalar.

SQLite — qisqacha

npx expo install expo-sqlite
import * as SQLite from 'expo-sqlite';

const db = await SQLite.openDatabaseAsync('dokon.db');
await db.execAsync(`CREATE TABLE IF NOT EXISTS eslatmalar (id INTEGER PRIMARY KEY, matn TEXT, sana TEXT)`);
await db.runAsync('INSERT INTO eslatmalar (matn, sana) VALUES (?, ?)', ['Non olish', new Date().toISOString()]);
const qatorlar = await db.getAllAsync<{ id: number; matn: string }>('SELECT * FROM eslatmalar ORDER BY id DESC');

Telefon ichidagi haqiqiy SQL baza — MySQL kursidagi bilimlar shu yerda ham ishlaydi. Placeholder ? — bu yerda ham majburiy.


Nima uchun shunday?

Nima uchun AsyncStorage asinxron, localStorage esa sinxron?

Brauzerdagi localStorage sinxron — va bu tez-tez tanqid qilinadigan dizayn xatosi: katta qiymatni o'qish butun sahifani qotiradi. Mobil ilovada UI ning har bir millisekundi muhim — 60 kadr/soniyada bitta kadr uchun 16 ms bor. Diskka murojaat esa ba'zan undan ko'p vaqt oladi. Asinxron API — o'qish/yozish fonda bo'ladi, interfeys esa silliq qoladi. (MMKV kabi kutubxonalar sinxron, lekin xotiraga xaritalangan fayl orqali juda tez ishlaydi — bu boshqa muhandislik yechimi.)


Xulosa

Eslab qoling:

  • AsyncStorage.setItem / getItem / removeItem — asinxron, faqat string
  • Ob'ektlar — JSON.stringify / JSON.parse, try/catch bilan
  • Tiplangan yordamchi — standart qiymat bilan
  • Onboarding, sozlamalar, qoralamalar — yaxshi nomzodlar
  • Zustand persist — avtomatik saqlash; hydration ni hisobga oling
  • Maxfiy — SecureStore; katta va so'rovli — SQLite; fayllar — FileSystem

Keyingi dars

35-dars: SecureStore — tokenlarni xavfsiz saqlash