React Native Integration & Best Practices: Data Abstractions
Storage Abstraction
To handle data persistence in a platform-agnostic way, we use a storage abstraction layer. This layer provides a unified API for accessing storage, regardless of the underlying platform. For native platforms, this might be a wrapper around @react-native-async-storage/async-storage, while for the web, it might use localStorage.
Implementation Pattern: Reactive Storage
Our native storage implementation (NativeStorage) wraps AsyncStorage with an in-memory cache and an event subscription system (SubscriberMap). This allows components to subscribe to storage updates, ensuring the UI stays in sync when data changes.
Example: Native Storage Class
import { SubscriberMap } from '@archibald/core';
import AsyncStorage from '@react-native-async-storage/async-storage';
class NativeStorage extends SubscriberMap<'update' | 'initialized'> {
protected cache = new Map<string, string>();
// Initialize: Load from disk to memory
public async init(key: string) {
const value = await AsyncStorage.getItem(key);
if (value) {
this.cache.set(key, value);
}
this.publish('initialized');
}
// Set: Update memory and disk, notify listeners
public async set(key: string, value: string | null) {
if (value == null) {
await AsyncStorage.removeItem(key);
this.cache.delete(key);
} else {
await AsyncStorage.setItem(key, value);
this.cache.set(key, value);
}
this.publish('update');
}
public get(key: string) {
return this.cache.get(key) ?? null;
}
}