Kodax

التخزين المحلي — أساسيات React Native

التخزين المحلي في React Native

1. AsyncStorage

npm install @react-native-async-storage/async-storage
// npx expo install @react-native-async-storage/async-storage
import AsyncStorage from '@react-native-async-storage/async-storage';

// حفظ قيمة نصية
await AsyncStorage.setItem('username', 'أحمد');

// حفظ كائن
const user = { name: 'أحمد', age: 25 };
await AsyncStorage.setItem('user', JSON.stringify(user));

// قراءة قيمة
const username = await AsyncStorage.getItem('username');

// قراءة كائن
const userJSON = await AsyncStorage.getItem('user');
const savedUser = userJSON ? JSON.parse(userJSON) : null;

// حذف قيمة
await AsyncStorage.removeItem('username');

// حذف كل البيانات
await AsyncStorage.clear();

// الحصول على كل المفاتيح
const keys = await AsyncStorage.getAllKeys();

// عمليات متعددة
await AsyncStorage.multiSet([
  ['key1', 'value1'],
  ['key2', 'value2'],
]);

const values = await AsyncStorage.multiGet(['key1', 'key2']);

Custom Hook للـ AsyncStorage

import { useState, useEffect } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';

function useStorage(key, initialValue) {
  const [value, setValue] = useState(initialValue);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    loadValue();
  }, []);

  const loadValue = async () => {
    try {
      const stored = await AsyncStorage.getItem(key);
      if (stored !== null) {
        setValue(JSON.parse(stored));
      }
    } catch (error) {
      console.error('Error loading:', error);
    } finally {
      setLoading(false);
    }
  };

  const saveValue = async (newValue) => {
    try {
      setValue(newValue);
      await AsyncStorage.setItem(key, JSON.stringify(newValue));
    } catch (error) {
      console.error('Error saving:', error);
    }
  };

  const removeValue = async () => {
    try {
      setValue(initialValue);
      await AsyncStorage.removeItem(key);
    } catch (error) {
      console.error('Error removing:', error);
    }
  };

  return { value, saveValue, removeValue, loading };
}

// الاستخدام
function SettingsScreen() {
  const { value: settings, saveValue: setSettings, loading } = useStorage('settings', {
    darkMode: false,
    notifications: true,
    language: 'ar',
  });

  if (loading) return <ActivityIndicator />;

  return (
    <View>
      <Switch
        value={settings.darkMode}
        onValueChange={(value) => 
          setSettings({ ...settings, darkMode: value })
        }
      />
    </View>
  );
}

2. Expo SecureStore (للبيانات الحساسة)

npx expo install expo-secure-store
import * as SecureStore from 'expo-secure-store';

// حفظ Token
await SecureStore.setItemAsync('authToken', 'your-secret-token');

// قراءة Token
const token = await SecureStore.getItemAsync('authToken');

// حذف Token
await SecureStore.deleteItemAsync('authToken');

// خيارات إضافية
await SecureStore.setItemAsync('pin', '1234', {
  keychainAccessible: SecureStore.WHEN_UNLOCKED,
});

3. MMKV (أسرع بكثير)

npm install react-native-mmkv
import { MMKV } from 'react-native-mmkv';

const storage = new MMKV();

// حفظ
storage.set('username', 'أحمد');
storage.set('age', 25);
storage.set('isLoggedIn', true);

// قراءة
const username = storage.getString('username');
const age = storage.getNumber('age');
const isLoggedIn = storage.getBoolean('isLoggedIn');

// حذف
storage.delete('username');

// التحقق من وجود مفتاح
const exists = storage.contains('username');

// كل المفاتيح
const keys = storage.getAllKeys();

// مسح الكل
storage.clearAll();

4. مثال تطبيقي: نظام Auth كامل

// services/authStorage.js
import * as SecureStore from 'expo-secure-store';
import AsyncStorage from '@react-native-async-storage/async-storage';

const AUTH_TOKEN_KEY = 'auth_token';
const USER_DATA_KEY = 'user_data';

export const AuthStorage = {
  // Token (آمن)
  async setToken(token) {
    await SecureStore.setItemAsync(AUTH_TOKEN_KEY, token);
  },

  async getToken() {
    return await SecureStore.getItemAsync(AUTH_TOKEN_KEY);
  },

  async removeToken() {
    await SecureStore.deleteItemAsync(AUTH_TOKEN_KEY);
  },

  // User Data (عادي)
  async setUser(user) {
    await AsyncStorage.setItem(USER_DATA_KEY, JSON.stringify(user));
  },

  async getUser() {
    const data = await AsyncStorage.getItem(USER_DATA_KEY);
    return data ? JSON.parse(data) : null;
  },

  async removeUser() {
    await AsyncStorage.removeItem(USER_DATA_KEY);
  },

  // تسجيل خروج كامل
  async logout() {
    await Promise.all([
      this.removeToken(),
      this.removeUser(),
    ]);
  },
};

// الاستخدام في Context
function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    loadUser();
  }, []);

  const loadUser = async () => {
    try {
      const token = await AuthStorage.getToken();
      if (token) {
        const userData = await AuthStorage.getUser();
        setUser(userData);
      }
    } finally {
      setLoading(false);
    }
  };

  const login = async (email, password) => {
    const response = await api.post('/login', { email, password });
    await AuthStorage.setToken(response.token);
    await AuthStorage.setUser(response.user);
    setUser(response.user);
  };

  const logout = async () => {
    await AuthStorage.logout();
    setUser(null);
  };

  return (
    <AuthContext.Provider value={{ user, login, logout, loading }}>
      {children}
    </AuthContext.Provider>
  );
}
اختبر فهمك