Ders İçeriği

Veri Depolama Nedir?

Mobil uygulamalarda veri depolama, kullanıcı verilerini, uygulama ayarlarını ve geçici bilgileri cihazda saklamak için kullanılır. React Native'de farklı depolama yöntemleri mevcuttur ve her birinin kendine özgü kullanım alanları vardır.

Depolama Türleri:
  • AsyncStorage: Basit anahtar-değer depolama
  • SecureStore: Güvenli veri depolama
  • SQLite: İlişkisel veritabanı
  • Realm: Nesne veritabanı
  • MMKV: Yüksek performanslı depolama

AsyncStorage ile Temel Depolama

AsyncStorage, React Native'in en basit depolama çözümüdür. Anahtar-değer çiftleri şeklinde veri saklar ve asenkron olarak çalışır.

// AsyncStorage kurulumu (React Native 0.60+) npm install @react-native-async-storage/async-storage // iOS için ek kurulum cd ios && pod install // AsyncStorage kullanımı import AsyncStorage from '@react-native-async-storage/async-storage'; // Veri kaydetme const storeData = async (key, value) => { try { // String değer kaydetme await AsyncStorage.setItem(key, value); // Obje kaydetme (JSON'a çevirerek) const jsonValue = JSON.stringify(value); await AsyncStorage.setItem(key, jsonValue); console.log('Veri kaydedildi'); } catch (error) { console.error('Veri kaydetme hatası:', error); } }; // Veri okuma const getData = async (key) => { try { const value = await AsyncStorage.getItem(key); if (value !== null) { // String değer return value; // JSON değer return JSON.parse(value); } } catch (error) { console.error('Veri okuma hatası:', error); } }; // Veri silme const removeData = async (key) => { try { await AsyncStorage.removeItem(key); console.log('Veri silindi'); } catch (error) { console.error('Veri silme hatası:', error); } }; // Tüm verileri silme const clearAll = async () => { try { await AsyncStorage.clear(); console.log('Tüm veriler silindi'); } catch (error) { console.error('Temizleme hatası:', error); } }; // Tüm anahtarları listeleme const getAllKeys = async () => { try { const keys = await AsyncStorage.getAllKeys(); console.log('Mevcut anahtarlar:', keys); return keys; } catch (error) { console.error('Anahtar listeleme hatası:', error); } }; // Çoklu veri işlemleri const multiSet = async () => { try { const pairs = [ ['@user_name', 'John Doe'], ['@user_email', 'john@example.com'], ['@user_age', '30'] ]; await AsyncStorage.multiSet(pairs); } catch (error) { console.error('Çoklu kaydetme hatası:', error); } }; const multiGet = async () => { try { const keys = ['@user_name', '@user_email', '@user_age']; const values = await AsyncStorage.multiGet(keys); // values: [['@user_name', 'John Doe'], ['@user_email', 'john@example.com'], ...] console.log('Çoklu veri:', values); return values; } catch (error) { console.error('Çoklu okuma hatası:', error); } };

Pratik Örnek: Kullanıcı Tercihleri Uygulaması

AsyncStorage kullanarak kullanıcı tercihlerini saklayan bir uygulama oluşturalım:

import React, { useState, useEffect } from 'react'; import { View, Text, Switch, TextInput, Button, StyleSheet, Alert, ScrollView, } from 'react-native'; import AsyncStorage from '@react-native-async-storage/async-storage'; const UserPreferencesApp = () => { const [preferences, setPreferences] = useState({ username: '', email: '', notifications: true, darkMode: false, language: 'tr', fontSize: 16, }); const [loading, setLoading] = useState(true); // Tercihleri yükle const loadPreferences = async () => { try { const savedPreferences = await AsyncStorage.getItem('@user_preferences'); if (savedPreferences) { const parsedPreferences = JSON.parse(savedPreferences); setPreferences(parsedPreferences); } } catch (error) { console.error('Tercihler yüklenirken hata:', error); Alert.alert('Hata', 'Tercihler yüklenemedi'); } finally { setLoading(false); } }; // Tercihleri kaydet const savePreferences = async (newPreferences) => { try { await AsyncStorage.setItem('@user_preferences', JSON.stringify(newPreferences)); setPreferences(newPreferences); Alert.alert('Başarılı', 'Tercihler kaydedildi'); } catch (error) { console.error('Tercihler kaydedilirken hata:', error); Alert.alert('Hata', 'Tercihler kaydedilemedi'); } }; // Tercihleri sıfırla const resetPreferences = async () => { Alert.alert( 'Tercihleri Sıfırla', 'Tüm tercihleri sıfırlamak istediğinizden emin misiniz?', [ { text: 'İptal', style: 'cancel' }, { text: 'Sıfırla', style: 'destructive', onPress: async () => { try { await AsyncStorage.removeItem('@user_preferences'); const defaultPreferences = { username: '', email: '', notifications: true, darkMode: false, language: 'tr', fontSize: 16, }; setPreferences(defaultPreferences); Alert.alert('Başarılı', 'Tercihler sıfırlandı'); } catch (error) { Alert.alert('Hata', 'Tercihler sıfırlanamadı'); } }, }, ] ); }; // Bileşen yüklendiğinde tercihleri getir useEffect(() => { loadPreferences(); }, []); // Tercih güncelleme fonksiyonu const updatePreference = (key, value) => { const newPreferences = { ...preferences, [key]: value }; savePreferences(newPreferences); }; if (loading) { return ( <View style={styles.loadingContainer}> <Text>Tercihler yükleniyor...</Text> </View> ); } return ( <ScrollView style={styles.container}> <Text style={styles.title}>Kullanıcı Tercihleri</Text> {/* Kullanıcı Bilgileri */} <View style={styles.section}> <Text style={styles.sectionTitle}>Kullanıcı Bilgileri</Text> <Text style={styles.label}>Kullanıcı Adı:</Text> <TextInput style={styles.input} value={preferences.username} onChangeText={(text) => updatePreference('username', text)} placeholder="Kullanıcı adınızı girin" /> <Text style={styles.label}>E-posta:</Text> <TextInput style={styles.input} value={preferences.email} onChangeText={(text) => updatePreference('email', text)} placeholder="E-posta adresinizi girin" keyboardType="email-address" /> </View> {/* Uygulama Ayarları */} <View style={styles.section}> <Text style={styles.sectionTitle}>Uygulama Ayarları</Text> <View style={styles.switchContainer}> <Text style={styles.label}>Bildirimler</Text> <Switch value={preferences.notifications} onValueChange={(value) => updatePreference('notifications', value)} /> </View> <View style={styles.switchContainer}> <Text style={styles.label}>Karanlık Mod</Text> <Switch value={preferences.darkMode} onValueChange={(value) => updatePreference('darkMode', value)} /> </View> <Text style={styles.label}>Font Boyutu: {preferences.fontSize}px</Text> <View style={styles.fontSizeContainer}> <Button title="-" onPress={() => updatePreference('fontSize', Math.max(12, preferences.fontSize - 2))} /> <Text style={[styles.sampleText, { fontSize: preferences.fontSize }]}> Örnek Metin </Text> <Button title="+" onPress={() => updatePreference('fontSize', Math.min(24, preferences.fontSize + 2))} /> </View> </View> {/* Önizleme */} <View style={[ styles.preview, { backgroundColor: preferences.darkMode ? '#2c3e50' : '#ecf0f1' } ]}> <Text style={[ styles.previewTitle, { color: preferences.darkMode ? 'white' : 'black', fontSize: preferences.fontSize + 4 } ]}> Önizleme </Text> <Text style={[ styles.previewText, { color: preferences.darkMode ? '#bdc3c7' : '#7f8c8d', fontSize: preferences.fontSize } ]}> Merhaba {preferences.username || 'Kullanıcı'}! </Text> <Text style={[ styles.previewText, { color: preferences.darkMode ? '#bdc3c7' : '#7f8c8d', fontSize: preferences.fontSize - 2 } ]}> Bildirimler: {preferences.notifications ? 'Açık' : 'Kapalı'} </Text> </View> {/* Sıfırlama Butonu */} <View style={styles.resetContainer}> <Button title="Tercihleri Sıfırla" onPress={resetPreferences} color="#e74c3c" /> </View> </ScrollView> ); }; const styles = StyleSheet.create({ container: { flex: 1, padding: 20, backgroundColor: '#f8f9fa', }, loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', }, title: { fontSize: 24, fontWeight: 'bold', textAlign: 'center', marginBottom: 20, color: '#2c3e50', }, section: { backgroundColor: 'white', padding: 15, borderRadius: 8, marginBottom: 15, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 3.84, elevation: 5, }, sectionTitle: { fontSize: 18, fontWeight: 'bold', marginBottom: 15, color: '#34495e', }, label: { fontSize: 16, fontWeight: '500', marginBottom: 5, color: '#2c3e50', }, input: { borderWidth: 1, borderColor: '#ddd', padding: 10, borderRadius: 5, marginBottom: 15, fontSize: 16, }, switchContainer: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 15, }, fontSizeContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 15, }, sampleText: { textAlign: 'center', color: '#2c3e50', }, preview: { padding: 20, borderRadius: 8, marginBottom: 20, }, previewTitle: { fontWeight: 'bold', marginBottom: 10, }, previewText: { marginBottom: 5, }, resetContainer: { marginBottom: 30, }, }); export default UserPreferencesApp;

AsyncStorage Simülasyonu

     

Henüz veri yok

Expo SecureStore ile Güvenli Depolama

Hassas veriler (şifreler, token'lar, kişisel bilgiler) için SecureStore kullanılmalıdır. Bu veriler şifrelenmiş olarak saklanır.

// Expo SecureStore kurulumu npx expo install expo-secure-store // SecureStore kullanımı import * as SecureStore from 'expo-secure-store'; // Güvenli veri kaydetme const saveSecureData = async (key, value) => { try { await SecureStore.setItemAsync(key, value); console.log('Güvenli veri kaydedildi'); } catch (error) { console.error('Güvenli kaydetme hatası:', error); } }; // Güvenli veri okuma const getSecureData = async (key) => { try { const result = await SecureStore.getItemAsync(key); return result; } catch (error) { console.error('Güvenli okuma hatası:', error); return null; } }; // Güvenli veri silme const deleteSecureData = async (key) => { try { await SecureStore.deleteItemAsync(key); console.log('Güvenli veri silindi'); } catch (error) { console.error('Güvenli silme hatası:', error); } }; // Kullanım örneği: Kullanıcı kimlik bilgileri const AuthService = { // Token kaydetme saveAuthToken: async (token) => { try { await SecureStore.setItemAsync('auth_token', token); } catch (error) { throw new Error('Token kaydedilemedi'); } }, // Token okuma getAuthToken: async () => { try { return await SecureStore.getItemAsync('auth_token'); } catch (error) { return null; } }, // Kullanıcı bilgileri kaydetme saveUserCredentials: async (username, password) => { try { await SecureStore.setItemAsync('username', username); await SecureStore.setItemAsync('password', password); } catch (error) { throw new Error('Kimlik bilgileri kaydedilemedi'); } }, // Kullanıcı bilgileri okuma getUserCredentials: async () => { try { const username = await SecureStore.getItemAsync('username'); const password = await SecureStore.getItemAsync('password'); return { username, password }; } catch (error) { return { username: null, password: null }; } }, // Çıkış yapma (tüm güvenli verileri sil) logout: async () => { try { await SecureStore.deleteItemAsync('auth_token'); await SecureStore.deleteItemAsync('username'); await SecureStore.deleteItemAsync('password'); } catch (error) { console.error('Çıkış yapılırken hata:', error); } }, }; // Biometric authentication ile güvenli depolama const saveBiometricData = async (key, value) => { try { await SecureStore.setItemAsync(key, value, { requireAuthentication: true, authenticationPrompt: 'Veriye erişmek için kimlik doğrulaması gerekli', }); } catch (error) { console.error('Biometric kaydetme hatası:', error); } };

SQLite ile İlişkisel Veritabanı

Karmaşık veri yapıları ve ilişkiler için SQLite kullanabilirsiniz. Bu, tam özellikli bir SQL veritabanıdır.

// SQLite kurulumu npx expo install expo-sqlite // SQLite kullanımı import * as SQLite from 'expo-sqlite'; // Veritabanı açma const db = SQLite.openDatabase('myapp.db'); // Tablo oluşturma const createTables = () => { db.transaction(tx => { // Kullanıcılar tablosu tx.executeSql( `CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT UNIQUE NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP );` ); // Görevler tablosu tx.executeSql( `CREATE TABLE IF NOT EXISTS tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, title TEXT NOT NULL, description TEXT, completed BOOLEAN DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users (id) );` ); }); }; // Kullanıcı ekleme const addUser = (name, email) => { return new Promise((resolve, reject) => { db.transaction(tx => { tx.executeSql( 'INSERT INTO users (name, email) VALUES (?, ?)', [name, email], (_, result) => { resolve(result.insertId); }, (_, error) => { reject(error); } ); }); }); }; // Kullanıcıları listeleme const getUsers = () => { return new Promise((resolve, reject) => { db.transaction(tx => { tx.executeSql( 'SELECT * FROM users ORDER BY created_at DESC', [], (_, result) => { const users = []; for (let i = 0; i < result.rows.length; i++) { users.push(result.rows.item(i)); } resolve(users); }, (_, error) => { reject(error); } ); }); }); }; // Görev ekleme const addTask = (userId, title, description) => { return new Promise((resolve, reject) => { db.transaction(tx => { tx.executeSql( 'INSERT INTO tasks (user_id, title, description) VALUES (?, ?, ?)', [userId, title, description], (_, result) => { resolve(result.insertId); }, (_, error) => { reject(error); } ); }); }); }; // Kullanıcının görevlerini getirme const getUserTasks = (userId) => { return new Promise((resolve, reject) => { db.transaction(tx => { tx.executeSql( `SELECT t.*, u.name as user_name FROM tasks t JOIN users u ON t.user_id = u.id WHERE t.user_id = ? ORDER BY t.created_at DESC`, [userId], (_, result) => { const tasks = []; for (let i = 0; i < result.rows.length; i++) { tasks.push(result.rows.item(i)); } resolve(tasks); }, (_, error) => { reject(error); } ); }); }); }; // Görev tamamlama const completeTask = (taskId) => { return new Promise((resolve, reject) => { db.transaction(tx => { tx.executeSql( 'UPDATE tasks SET completed = 1 WHERE id = ?', [taskId], (_, result) => { resolve(result.rowsAffected > 0); }, (_, error) => { reject(error); } ); }); }); }; // Veritabanı sıfırlama const resetDatabase = () => { db.transaction(tx => { tx.executeSql('DROP TABLE IF EXISTS tasks'); tx.executeSql('DROP TABLE IF EXISTS users'); }); createTables(); }; // React bileşeninde kullanım const DatabaseExample = () => { const [users, setUsers] = useState([]); const [tasks, setTasks] = useState([]); useEffect(() => { createTables(); loadUsers(); }, []); const loadUsers = async () => { try { const userList = await getUsers(); setUsers(userList); } catch (error) { console.error('Kullanıcılar yüklenirken hata:', error); } }; const handleAddUser = async (name, email) => { try { await addUser(name, email); loadUsers(); Alert.alert('Başarılı', 'Kullanıcı eklendi'); } catch (error) { Alert.alert('Hata', 'Kullanıcı eklenemedi'); } }; // Component render... };

📊 Depolama Yöntemleri Karşılaştırması

YöntemGüvenlikPerformansKullanım AlanıVeri Boyutu
AsyncStorageDüşükOrtaBasit ayarlar, tercihlerKüçük
SecureStoreYüksekOrtaŞifreler, token'larKüçük
SQLiteOrtaYüksekKarmaşık veri yapılarıBüyük
RealmOrtaÇok YüksekNesne veritabanıBüyük
MMKVDüşükÇok YüksekHızlı anahtar-değerOrta

MMKV ile Yüksek Performanslı Depolama

MMKV, AsyncStorage'a göre çok daha hızlı olan bir anahtar-değer depolama çözümüdür:

// MMKV kurulumu npm install react-native-mmkv // iOS için ek kurulum cd ios && pod install // MMKV kullanımı import { MMKV } from 'react-native-mmkv'; // MMKV instance oluşturma const storage = new MMKV(); // Şifrelenmiş storage const encryptedStorage = new MMKV({ id: 'encrypted-storage', encryptionKey: 'your-encryption-key' }); // Veri kaydetme storage.set('user.name', 'John Doe'); storage.set('user.age', 30); storage.set('user.isActive', true); // Obje kaydetme const userObject = { name: 'John', email: 'john@example.com' }; storage.set('user.profile', JSON.stringify(userObject)); // Veri okuma const userName = storage.getString('user.name'); const userAge = storage.getNumber('user.age'); const isActive = storage.getBoolean('user.isActive'); // Obje okuma const userProfileString = storage.getString('user.profile'); const userProfile = userProfileString ? JSON.parse(userProfileString) : null; // Veri silme storage.delete('user.name'); // Tüm verileri silme storage.clearAll(); // Tüm anahtarları listeleme const allKeys = storage.getAllKeys(); // Veri varlığını kontrol etme const hasUserName = storage.contains('user.name'); // React Hook ile MMKV kullanımı import { useMMKVString, useMMKVNumber, useMMKVBoolean } from 'react-native-mmkv'; const UserComponent = () => { const [username, setUsername] = useMMKVString('user.name'); const [age, setAge] = useMMKVNumber('user.age'); const [notifications, setNotifications] = useMMKVBoolean('user.notifications'); return ( <View> <TextInput value={username} onChangeText={setUsername} placeholder="Kullanıcı adı" /> <Text>Yaş: {age}</Text> <Switch value={notifications} onValueChange={setNotifications} /> </View> ); }; // Performans karşılaştırması const performanceTest = () => { const iterations = 1000; // MMKV test const mmkvStart = Date.now(); for (let i = 0; i < iterations; i++) { storage.set(`test_${i}`, `value_${i}`); } const mmkvTime = Date.now() - mmkvStart; console.log(`MMKV: ${mmkvTime}ms for ${iterations} operations`); // AsyncStorage karşılaştırması için benzer test yapılabilir };

Sonraki Adımlar

Bu derste veri depolama yöntemlerini öğrendiniz. Bir sonraki derste cihaz özelliklerine erişim konusunu ele alacak ve kamera, konum, bildirimler gibi native özellikleri nasıl kullanacağınızı öğreneceksiniz.

Bu Derste Öğrendikleriniz:
  • AsyncStorage ile basit veri depolama
  • SecureStore ile güvenli veri saklama
  • SQLite ile ilişkisel veritabanı
  • MMKV ile yüksek performanslı depolama
  • Depolama yöntemlerinin karşılaştırması
  • Pratik kullanım örnekleri