Fluxy
Fundamentals

Data & Repository

Managing offline data flow with FluxyRepository.

Data & Repository

The FluxRepository is a foundational abstraction in Fluxy designed for building robust, offline-first applications. It connects your UI to remote data sources (like REST APIs or Databases) while synchronizing with local storage (like SQLite or Shared Preferences).

FluxRepository

A FluxRepository is essentially a FluxController enhanced with data management capabilities:

  • Offline Sync Logic: Built-in support for "Local First, Then Remote" synchronization.
  • Stream Binding: Automatic lifecycle management for database streams (e.g., Firebase, realm).
  • Data Guard Integration: Uses FluxyDataGuard for retries and resilience.

Creating a Repository

Extend FluxRepository and implement the sync() usage or bind streams directly.

class UserRepository extends FluxRepository {
  // Define Reactive State
  final user = flux<User?>(null);

  @override
  void onInit() {
    // Automatically load data when repo starts
    loadUser();
  }

  Future<void> loadUser() async {
    // Use DataGuard for SWR (Stale-While-Revalidate)
    await FluxyDataGuard.swr(
      local: _fetchLocalUser(),
      remote: _fetchRemoteUser(),
      onData: (data) => user.value = data,
    );
  }

  Future<User?> _fetchLocalUser() async {
    // Fetch from Hive/SQLite
  }

  Future<User> _fetchRemoteUser() async {
    // Fetch from API
    return await Fx.http.get('/me');
  }
}

Stream Subscriptions

If you work with real-time databases (like Firebase), manual subscription management is error-prone. FluxRepository simplifies this with bindStream.

class ChatRepository extends FluxRepository {
  final messages = flux<List<Message>>([]);

  void listenToChat(String chatId) {
    // This subscription is automatically canceled when 
    // the repository is disposed. No memory leaks!
    bindStream(
      MyDatabase.chatStream(chatId), 
      messages
    );
  }
}

Every FluxRepository comes with a built-in isOnline signal. This is automatically synchronized with the global connectivity engine, allowing you to build resilient, offline-ready logic with zero configuration.

Use Case: Automated Synchronization

A common requirement is to "Queue" data while offline and "Flush" it once the connection returns.

class TaskRepository extends FluxRepository {
  final tasks = fluxList<Task>([], persistKey: 'offline_tasks');

  @override
  void onInit() {
    super.onInit();
    
    // Automatically trigger a sync whenever the device joins a network
    fluxEffect(() {
      if (isOnline.value && tasks.isNotEmpty) {
        _uploadPendingTasks();
      }
    });
  }

  Future<void> _uploadPendingTasks() async {
    Fx.toast.info("Connection Restored. Syncing ${tasks.length} items...");
    
    for (var task in tasks) {
      final success = await Fx.http.post('/tasks', body: task.toJson());
      if (success) tasks.remove(task);
    }
  }
}

Data Layer vs Service Layer

It is easy to confuse a FluxRepository with a Service. In Fluxy, they have distinct roles:

  • Repository (The Manager): Manages Business Models and feature-specific data (e.g., UserRepository, PaymentRepository).
  • Service (The Tool): Provides Generic Capabilities used across the app (e.g., logger_service.dart, api_service.dart).

Rule: If your logic involves fetching "Products" or "Orders," it belongs in a Repository. If your logic involves "Sending an Analytics Event" or "Opening the Camera," it belongs in a Service.

On this page