React Native AsyncStorage #

概述 #

AsyncStorage 是 React Native 的异步、持久化键值存储系统。它用于存储小型数据,如用户偏好、令牌、缓存等。

安装 #

bash
npm install @react-native-async-storage/async-storage

iOS 需要 pod install:

bash
cd ios && pod install

基本操作 #

存储数据 #

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

const storeData = async (key: string, value: string) => {
  try {
    await AsyncStorage.setItem(key, value);
    console.log('Data saved successfully');
  } catch (error) {
    console.error('Error saving data:', error);
  }
};

// 使用示例
await storeData('username', 'john_doe');

读取数据 #

tsx
const getData = async (key: string): Promise<string | null> => {
  try {
    const value = await AsyncStorage.getItem(key);
    if (value !== null) {
      return value;
    }
    return null;
  } catch (error) {
    console.error('Error reading data:', error);
    return null;
  }
};

// 使用示例
const username = await getData('username');
console.log('Username:', username);

删除数据 #

tsx
const removeData = async (key: string) => {
  try {
    await AsyncStorage.removeItem(key);
    console.log('Data removed successfully');
  } catch (error) {
    console.error('Error removing data:', error);
  }
};

// 使用示例
await removeData('username');

清空所有数据 #

tsx
const clearAll = async () => {
  try {
    await AsyncStorage.clear();
    console.log('All data cleared');
  } catch (error) {
    console.error('Error clearing data:', error);
  }
};

存储对象 #

AsyncStorage 只能存储字符串,需要使用 JSON 序列化。

存储对象 #

tsx
interface User {
  id: string;
  name: string;
  email: string;
}

const storeUser = async (user: User) => {
  try {
    const jsonValue = JSON.stringify(user);
    await AsyncStorage.setItem('user', jsonValue);
  } catch (error) {
    console.error('Error storing user:', error);
  }
};

读取对象 #

tsx
const getUser = async (): Promise<User | null> => {
  try {
    const jsonValue = await AsyncStorage.getItem('user');
    return jsonValue != null ? JSON.parse(jsonValue) : null;
  } catch (error) {
    console.error('Error getting user:', error);
    return null;
  }
};

存储数组 #

tsx
interface Todo {
  id: string;
  text: string;
  completed: boolean;
}

const storeTodos = async (todos: Todo[]) => {
  try {
    await AsyncStorage.setItem('todos', JSON.stringify(todos));
  } catch (error) {
    console.error('Error storing todos:', error);
  }
};

const getTodos = async (): Promise<Todo[]> => {
  try {
    const jsonValue = await AsyncStorage.getItem('todos');
    return jsonValue ? JSON.parse(jsonValue) : [];
  } catch (error) {
    console.error('Error getting todos:', error);
    return [];
  }
};

批量操作 #

批量存储 #

tsx
const storeMultiple = async (data: Record<string, string>) => {
  try {
    const pairs: [string, string][] = Object.entries(data);
    await AsyncStorage.multiSet(pairs);
    console.log('Multiple items stored');
  } catch (error) {
    console.error('Error storing multiple items:', error);
  }
};

// 使用示例
await storeMultiple({
  username: 'john_doe',
  email: 'john@example.com',
  theme: 'dark',
});

批量读取 #

tsx
const getMultiple = async (keys: string[]): Promise<Record<string, string | null>> => {
  try {
    const pairs = await AsyncStorage.multiGet(keys);
    const result: Record<string, string | null> = {};
    pairs.forEach(([key, value]) => {
      result[key] = value;
    });
    return result;
  } catch (error) {
    console.error('Error getting multiple items:', error);
    return {};
  }
};

// 使用示例
const data = await getMultiple(['username', 'email', 'theme']);
console.log(data);

批量删除 #

tsx
const removeMultiple = async (keys: string[]) => {
  try {
    await AsyncStorage.multiRemove(keys);
    console.log('Multiple items removed');
  } catch (error) {
    console.error('Error removing multiple items:', error);
  }
};

获取所有键 #

tsx
const getAllKeys = async (): Promise<string[]> => {
  try {
    const keys = await AsyncStorage.getAllKeys();
    return keys;
  } catch (error) {
    console.error('Error getting all keys:', error);
    return [];
  }
};

封装存储服务 #

创建一个可复用的存储服务:

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

class StorageService {
  private static instance: StorageService;

  private constructor() {}

  static getInstance(): StorageService {
    if (!StorageService.instance) {
      StorageService.instance = new StorageService();
    }
    return StorageService.instance;
  }

  async set<T>(key: string, value: T): Promise<void> {
    try {
      const jsonValue = JSON.stringify(value);
      await AsyncStorage.setItem(key, jsonValue);
    } catch (error) {
      console.error(`Error saving ${key}:`, error);
      throw error;
    }
  }

  async get<T>(key: string): Promise<T | null> {
    try {
      const jsonValue = await AsyncStorage.getItem(key);
      return jsonValue ? JSON.parse(jsonValue) : null;
    } catch (error) {
      console.error(`Error reading ${key}:`, error);
      return null;
    }
  }

  async remove(key: string): Promise<void> {
    try {
      await AsyncStorage.removeItem(key);
    } catch (error) {
      console.error(`Error removing ${key}:`, error);
      throw error;
    }
  }

  async clear(): Promise<void> {
    try {
      await AsyncStorage.clear();
    } catch (error) {
      console.error('Error clearing storage:', error);
      throw error;
    }
  }

  async getAllKeys(): Promise<string[]> {
    try {
      return await AsyncStorage.getAllKeys();
    } catch (error) {
      console.error('Error getting all keys:', error);
      return [];
    }
  }
}

export default StorageService.getInstance();

使用封装服务 #

tsx
import storage from './StorageService';

const saveUser = async (user: User) => {
  await storage.set('user', user);
};

const loadUser = async (): Promise<User | null> => {
  return await storage.get<User>('user');
};

使用 Hook #

创建自定义 Hook 简化使用:

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

function useStorage<T>(key: string, initialValue: T) {
  const [storedValue, setStoredValue] = useState<T>(initialValue);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const loadValue = async () => {
      try {
        const jsonValue = await AsyncStorage.getItem(key);
        if (jsonValue !== null) {
          setStoredValue(JSON.parse(jsonValue));
        }
      } catch (error) {
        console.error(`Error loading ${key}:`, error);
      } finally {
        setLoading(false);
      }
    };
    loadValue();
  }, [key]);

  const setValue = async (value: T) => {
    try {
      setStoredValue(value);
      await AsyncStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
      console.error(`Error saving ${key}:`, error);
    }
  };

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

  return {value: storedValue, setValue, removeValue, loading};
}

export default useStorage;

使用 Hook #

tsx
import React from 'react';
import {View, Text, Button, TextInput, StyleSheet} from 'react-native';
import useStorage from './useStorage';

const SettingsScreen = () => {
  const {value: theme, setValue: setTheme, loading} = useStorage('theme', 'light');
  const {value: username, setValue: setUsername} = useStorage('username', '');

  if (loading) {
    return <Text>Loading...</Text>;
  }

  return (
    <View style={styles.container}>
      <Text>Theme: {theme}</Text>
      <Button
        title="Toggle Theme"
        onPress={() => setTheme(theme === 'light' ? 'dark' : 'light')}
      />
      
      <TextInput
        value={username}
        onChangeText={setUsername}
        placeholder="Username"
        style={styles.input}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 16,
  },
  input: {
    height: 48,
    borderWidth: 1,
    borderColor: '#ccc',
    borderRadius: 8,
    paddingHorizontal: 16,
    marginTop: 16,
  },
});

export default SettingsScreen;

加密存储 #

对于敏感数据,需要加密存储:

bash
npm install react-native-keychain
tsx
import * as Keychain from 'react-native-keychain';

const saveSecureValue = async (key: string, value: string) => {
  try {
    await Keychain.setGenericPassword(key, value, {
      service: key,
    });
  } catch (error) {
    console.error('Error saving secure value:', error);
  }
};

const getSecureValue = async (key: string): Promise<string | null> => {
  try {
    const result = await Keychain.getGenericPassword({service: key});
    return result ? result.password : null;
  } catch (error) {
    console.error('Error getting secure value:', error);
    return null;
  }
};

const removeSecureValue = async (key: string) => {
  try {
    await Keychain.resetGenericPassword({service: key});
  } catch (error) {
    console.error('Error removing secure value:', error);
  }
};

缓存管理 #

带过期时间的缓存 #

tsx
interface CacheItem<T> {
  data: T;
  timestamp: number;
  expiresIn: number;
}

const setCache = async <T>(key: string, data: T, expiresIn: number) => {
  const item: CacheItem<T> = {
    data,
    timestamp: Date.now(),
    expiresIn,
  };
  await AsyncStorage.setItem(key, JSON.stringify(item));
};

const getCache = async <T>(key: string): Promise<T | null> => {
  try {
    const jsonValue = await AsyncStorage.getItem(key);
    if (!jsonValue) return null;

    const item: CacheItem<T> = JSON.parse(jsonValue);
    const now = Date.now();

    if (now - item.timestamp > item.expiresIn) {
      await AsyncStorage.removeItem(key);
      return null;
    }

    return item.data;
  } catch (error) {
    return null;
  }
};

// 使用示例:缓存 API 响应 5 分钟
const fetchUserWithCache = async (userId: string) => {
  const cacheKey = `user_${userId}`;
  const cached = await getCache<User>(cacheKey);
  
  if (cached) {
    return cached;
  }

  const user = await fetchUser(userId);
  await setCache(cacheKey, user, 5 * 60 * 1000);
  return user;
};

最佳实践 #

键命名规范 #

tsx
const STORAGE_KEYS = {
  USER: '@app:user',
  TOKEN: '@app:token',
  THEME: '@app:theme',
  CART: '@app:cart',
  NOTIFICATIONS: '@app:notifications',
} as const;

// 使用
await AsyncStorage.setItem(STORAGE_KEYS.USER, jsonValue);

错误处理 #

tsx
const safeStorage = {
  async get<T>(key: string): Promise<T | null> {
    try {
      const value = await AsyncStorage.getItem(key);
      return value ? JSON.parse(value) : null;
    } catch (error) {
      console.error(`Storage get error for ${key}:`, error);
      return null;
    }
  },

  async set<T>(key: string, value: T): Promise<boolean> {
    try {
      await AsyncStorage.setItem(key, JSON.stringify(value));
      return true;
    } catch (error) {
      console.error(`Storage set error for ${key}:`, error);
      return false;
    }
  },
};

数据迁移 #

tsx
const migrateData = async () => {
  const version = await AsyncStorage.getItem('@app:version');
  
  if (!version) {
    // 首次安装,初始化数据
    await AsyncStorage.setItem('@app:version', '1.0.0');
  } else if (version === '1.0.0') {
    // 从 1.0.0 迁移到 1.1.0
    const oldData = await AsyncStorage.getItem('old_key');
    if (oldData) {
      await AsyncStorage.setItem('new_key', oldData);
      await AsyncStorage.removeItem('old_key');
    }
    await AsyncStorage.setItem('@app:version', '1.1.0');
  }
};

限制 #

  • 大小限制:Android 默认 6MB,iOS 无限制但建议不超过 2MB
  • 性能:大量数据时性能下降,建议使用数据库
  • 同步:所有操作都是异步的

总结 #

AsyncStorage 是 React Native 的基础存储方案:

  • 适合存储小型数据
  • 支持字符串、对象、数组
  • 提供批量操作
  • 敏感数据使用 Keychain

对于大量数据或复杂查询,建议使用 SQLite 或 Realm。

继续学习 网络请求,了解 API 调用和数据处理。

最后更新:2026-03-28