Fluxy
Fundamentals

Reactive Architecture

The philosophy behind Fluxy's reactivity and state management.

Reactive Architecture

The core philosophy of Fluxy is to minimize re-renders and make data flow explicit.

The Reactive Graph

Fluxy uses a Signal Graph (Flux System) to track dependencies. Every Flux, FluxComputed, and FluxEffect is a node in this graph.

This is different from traditional setState() which rebuilds entire widget subtrees.

When a Flux updates, it notifies only its direct dependents. If a FluxComputed value depends on that signal, it recalculates. If a FluxEffect uses that signal, it re-runs. This ensures that only the necessary parts of your UI update.

Visualizing the Flow

graph TD
    A[User Action (Tap)] -->|Triggers| B[FluxController Method]
    B -->|Updates| C[Flux<T> Signal]
    C -->|Notifies| D{Reactive Graph}
    D -->|Rebuilds| E[Fx Widget (UI)]
    E -->|Renders| F[Flutter Engine]
    
    subgraph "Logic Layer"
    B
    C
    end
    
    subgraph "View Layer"
    E
    A
    end

Architectural Authority

Fluxy v0.1.9 formalizes the Architectural Authority of the framework, moving from a library to an application platform. It enforces clean separation of concerns through standardized base classes:

  • Logic Layer (FluxController): Handles business logic with native lifecycle hooks (onInit, onReady, onDispose).
  • Data Layer (FluxRepository): Manages offline-first data orchestration with automatic Local/Remote synchronization.
  • Extension Layer (FluxyPlugin): Modular interface for building framework extensions that hook into the global lifecycle (onRegister, onAppReady, onDispose).
  • Feature-First Structure: Enforces a lib/features and lib/core directory convention for scalable, enterprise-grade development.

Single Engine Philosophy

Instead of relying on multiple disjointed state management solutions, navigation libraries, and networking engines, everything in Fluxy is unified under a single Engine instance. This engine coordinates:

  • State Updates: Automatic batching and dependency tracking.
  • Networking: Native FluxyHttp engine with global interceptors.
  • Routing: Managing the navigation stack and history with automatic controller factory.
  • Theming: Applying global styles and responsive breakpoints.
  • OTA Updates: Handling remote manifest downloads and hot-swaps.

This unification reduces complexity and ensures that all parts of your application work together seamlessly.

Performance First

Performance is built-in, not an afterthought.

  • Fine-Grained Updates: Only change the specific text node or style property that needs to update.
  • Lazy Evaluation: Computed values are only calculated when accessed.
  • Zero Overhead: While the developer experience is rich, the runtime cost is minimal.

Flat Widget Tree (Attribute Accumulation)

Fluxy v0.1.6 optimizes UI performance through a Flat Widget Tree. Unlike traditional modifier-based frameworks that wrap widgets in nested layers (Padding > DecoratedBox > Opacity), Fluxy uses an Attribute Accumulation pattern.

How it Works

When you chain modifiers:

Fx.box()
  .p(16)
  .bg(Colors.blue)
  .rounded(12)
  .shadow.lg

The engine accumulates these attributes into a single internal style object. This results in far fewer widgets in the element tree, leading to better memory usage and faster layout passes.

graph LR
    subgraph "Traditional Approach"
    A[Padding] --> B[DecoratedBox]
    B --> C[Opacity]
    C --> D[Child]
    end
    
    subgraph "Fluxy Approach"
    E[FxBox (With Styles)] --> F[Child]
    end

The Master Feature Structure

Fluxy enforces a "Feature-First" architecture. Instead of putting all controllers in one folder and all views in another, we group them by business utility. Here is a complete representation of a Product Catalog feature.

Folder Structure

lib/
└── features/
    └── catalog/
        ├── catalog.controller.dart  # Business Logic
        ├── catalog.repository.dart  # Data Orchestration
        ├── catalog.view.dart        # UI Layer 
        └── widgets/                 # Child components
            └── product_card.dart

Implementation Example

// 1. DATA LAYER: catalog.repository.dart
class CatalogRepository extends FluxRepository {
  // Offline-first storage automatically managed
  late final products = flux([], persistKey: 'cached_products');

  Future<void> refresh() async {
    final data = await Fx.http.get('/api/products');
    products.value = data; // Triggers UI across the whole app
  }
}

// 2. LOGIC LAYER: catalog.controller.dart
class CatalogController extends FluxController {
  final repo = use<CatalogRepository>();
  final searchQuery = flux('', label: 'catalog_search');

  // Computed: Real-time filtering with 0 listener boilerplate
  late final filteredProducts = fluxComputed(() {
    if (searchQuery.value.isEmpty) return repo.products.value;
    return repo.products.value.where((p) => p.name.contains(searchQuery.value)).toList();
  });

  void onProductTap(Product p) => Fx.platform.haptics.heavy();
}

// 3. UI LAYER: catalog.view.dart
class CatalogView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Controller is automatically found in the registry
    final logic = use<CatalogController>();

    return Fx.layout(
      // Responsive layout: Mobile vs Tablet/Desktop
      mobile: Fx.col(
        children: [
          Fx.field(logic.searchQuery).placeholder("Search..."),
          
          Fx(() => Fx.col(
            children: logic.filteredProducts.value.map((p) => ProductCard(p)).toList(),
          )).scrollable(),
        ],
      ),
    );
  }
}

This structural pattern ensures that your code is modular, testable, and scales to hundreds of features without becoming a "Spaghetti" codebase.


Data vs Services (The Toolbelt vs The Manager)

In Fluxy, we distinguish between Repositories (Data Layer) and Services (Infrastructure Layer).

ConceptRoleExample
RepositoryThe Manager: Owns feature-specific data (Products, Users).catalog.repository.dart
ServiceThe Tool: Provides global capabilities (Camera, Logs, Auth).auth.service.dart
  • Rule of Thumb: If it manages your business models, it's a Repository. If it provides a generic hardware or utility function, it's a Service.

Routing Strategy (Centralized vs Isolated)

Fluxy does not mandate a specific location for routes. Choose the strategy that matches your team size.

1. Centralized Strategy (Small Teams)

Keep a single lib/core/routes.dart file. It's easier to see the entire application flow in one place.

2. Isolated Strategy (Enterprise Teams)

Each feature folder owns a feature.route.dart file. This prevents merge conflicts when 10+ developers are working on different modules simultaneously.

[!TIP] Start with a Centralized route file. Only move to Isolated routes when your feature folder becomes complex or your team grows.

On this page