reactive_flutter 1.0.1 copy "reactive_flutter: ^1.0.1" to clipboard
reactive_flutter: ^1.0.1 copied to clipboard

A lightweight auto-tracking reactive state management library for Flutter.

[reactive_flutter banner]

pub package likes popularity pub points


About #

A lightweight auto-tracking reactive state management library for Flutter.

reactive_flutter provides:

  • Reactive state containers
  • Automatic widget rebuild tracking
  • Lightweight dependency injection
  • Page-based pagination
  • Cursor-based pagination
  • Minimal boilerplate
  • Zero code generation

Features #

✅ Automatic dependency tracking
✅ Lightweight and fast
✅ No BuildContext required for state access
✅ No manual dependency lists
✅ Page-based pagination
✅ Cursor-based pagination
✅ Simple dependency injection
✅ Easy to learn and use


Installation #

Add the package to your pubspec.yaml:

dependencies:
  reactive_flutter: latest_version

Then run:

flutter pub get

Import the package:

import 'package:reactive_flutter/reactive_flutter.dart';

Reactive State #

Reactive<T> is a lightweight reactive value holder.

Whenever the value changes, widgets that depend on it automatically rebuild.

Create Reactive Values #

final Reactive<int> counter = Reactive<int>(0);
final Reactive<String> title = Reactive<String>('Flutter');
final Reactive<bool> isDark = Reactive<bool>(false);

Reading Values #

Use .value to access the current value.

print(counter.value);

Updating Values #

Update the value using .value.

counter.value = counter.value + 1;

isDark.value = true;

Silent Updates #

Use setSilent() to update a value without notifying listeners.

counter.setSilent(100);

Watch Widget #

Watch automatically rebuilds whenever a reactive value used inside the builder changes.

No dependency list is required.

Basic Example #

Watch(
  builder: () {
    return Text('${counter.value}');
  },
)

Multiple Reactive Dependencies #

Watch(
  builder: () {
    return Column(
      children: [
        Text('${counter.value}'),
        Text(title.value),
        Switch(
          value: isDark.value,
          onChanged: (value) {
            isDark.value = value;
          },
        ),
      ],
    );
  },
)

Conditional Tracking #

Dependencies are tracked automatically based on what is accessed during build.

Watch(
  builder: () {
    return isDark.value
        ? Text('Dark Mode')
        : Text('Light Mode');
  },
)

Only the reactive values used in the active branch are subscribed.


Dependency Injection #

ReactiveInjector is a lightweight service locator.

Supports:

  • Singleton registration
  • Transient registration
  • Dependency lookup
  • Reset
  • Unregister
  • Clear all

Register Singleton #

Singletons reuse the same instance.

ReactiveInjector.singleton<ApiService>(
  () => ApiService(),
);

Retrieve the dependency:

final ApiService api = ReactiveInjector.find<ApiService>();

Register Transient #

Transient dependencies create a new instance every time.

ReactiveInjector.transient<UserRepository>(
  () => UserRepository(),
);

Check Registration #

final bool exists = ReactiveInjector.isRegistered<ApiService>();

Reset Singleton #

Clears the cached singleton instance.

ReactiveInjector.reset<ApiService>();

Unregister Dependency #

ReactiveInjector.unregister<ApiService>();

Clear All Dependencies #

ReactiveInjector.clear();

Page-Based Pagination #

ReactivePagination<T> helps manage paginated APIs using page numbers.

Create Pagination Controller #

final ReactivePagination<User> pagination = ReactivePagination<User>(
  perPage: 20,
  fetcher: (page, perPage) async {
    return api.fetchUsers(page, perPage);
  },
);

Initialize Pagination #

await pagination.init();

Refresh Pagination #

await pagination.refresh();

Load More #

await pagination.fetchMore();

Access Pagination State #

pagination.items
pagination.isLoading
pagination.isMoreLoading
pagination.hasMore
pagination.error
pagination.totalFetched
pagination.isEmpty

Watch Pagination State #

Watch(
  builder: () {
    if (pagination.isLoading) {
      return const CircularProgressIndicator();
    }

    return ListView.builder(
      itemCount: pagination.items.length,
      itemBuilder: (context, index) {
        final user = pagination.items[index];

        return ListTile(
          title: Text(user.name),
        );
      },
    );
  },
)

Cursor-Based Pagination #

ReactiveCursorPagination<T, C> supports APIs that use cursors.

C represents the cursor type.

Examples:

  • String
  • int
  • DateTime
  • DocumentSnapshot (Firebase Firestore)
  • Custom cursor model

Create Cursor Pagination #

final ReactiveCursorPagination<User, String> pagination =
    ReactiveCursorPagination<User, String>(
  perPage: 20,
  fetcher: (perPage, cursor) async {
    return api.fetchUsers(perPage, cursor);
  },
);

PaginationResult #

Cursor pagination fetchers return PaginationResult<T, C>.

PaginationResult<User, String>(
  items: users,
  nextCursor: nextCursor,
)

Cursor Pagination State #

pagination.items
pagination.cursor
pagination.isLoading
pagination.isMoreLoading
pagination.hasMore
pagination.error
pagination.totalFetched
pagination.isEmpty

Example App #

import 'package:flutter/material.dart';
import 'package:reactive_flutter/reactive_flutter.dart';

final Reactive<int> counter = Reactive<int>(0);

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Reactive State'),
        ),
        body: Center(
          child: Watch(
            builder: () {
              return Text(
                '${counter.value}',
                style: const TextStyle(fontSize: 40),
              );
            },
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            counter.value++;
          },
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}

API Overview #

Reactive #

Function Description
value Get or update the reactive value
setSilent() Update value without notifying listeners
toString() Returns debug string

Watch #

Property Description
builder Widget builder automatically tracked

ReactiveInjector #

Function Description
singleton() Register singleton dependency
transient() Register transient dependency
find() Resolve dependency
isRegistered() Check if dependency exists
reset() Reset singleton instance
unregister() Remove dependency
clear() Remove all dependencies

ReactivePagination #

Function Description
init() Load first page
refresh() Reload from beginning
fetchMore() Load next page

ReactiveCursorPagination #

Function Description
init() Load first page
refresh() Reload from beginning
fetchMore() Load next cursor page

Why reactive_flutter? #

reactive_flutter focuses on simplicity.

Unlike larger state management solutions, it provides:

  • Minimal API surface
  • Automatic dependency tracking
  • No boilerplate
  • No generators
  • No annotations
  • Lightweight architecture
  • Easy integration into existing apps

Perfect for:

  • Small apps
  • Medium apps
  • Prototypes
  • Utility apps
  • Feature modules
  • Developers who prefer minimalism

Performance #

reactive_flutter is designed to stay lightweight and fast.

Why it performs well #

  • No reflection
  • No code generation
  • No runtime dependency graph building
  • Fine-grained rebuild tracking
  • Only widgets that access a reactive value rebuild
  • Conditional dependencies are handled automatically

Architecture #

Reactive<T>
    ↓
ReactiveTracker
    ↓
Watch Widget
    ↓
Automatic Rebuild

How it works #

  1. Watch starts dependency tracking.
  2. Any accessed Reactive.value registers itself.
  3. Watch subscribes only to accessed reactives.
  4. When a reactive changes, only subscribed widgets rebuild.

Comparison #

Feature reactive_flutter GetX Riverpod Provider
Auto tracking ⚠️ Partial
Code generation ⚠️ Optional
Boilerplate Very Low Low Medium Medium
Dependency injection
Pagination helpers
Learning curve Easy Easy Medium Easy
Lightweight ⚠️ ⚠️

Advanced Reactive Example #

final Reactive<List<String>> todos = Reactive<List<String>>([]);

void addTodo(String value) {
  todos.value = [...todos.value, value];
}

void removeTodo(String value) {
  todos.value = todos.value.where((e) => e != value).toList();
}

Nested Watch Example #

Watch(
  builder: () {
    return Column(
      children: [
        Watch(
          builder: () {
            return Text(counter.value.toString());
          },
        ),
        Watch(
          builder: () {
            return Text(title.value);
          },
        ),
      ],
    );
  },
)

Scroll Pagination Example #

class UsersPage extends StatefulWidget {
  const UsersPage({super.key});

  @override
  State<UsersPage> createState() => _UsersPageState();
}

class _UsersPageState extends State<UsersPage> {
  final ScrollController _controller = ScrollController();

  final ReactivePagination<User> pagination = ReactivePagination<User>(
    perPage: 20,
    fetcher: (page, limit) async {
      return api.fetchUsers(page, limit);
    },
  );

  @override
  void initState() {
    super.initState();

    pagination.init();

    _controller.addListener(() {
      if (_controller.position.pixels >=
          _controller.position.maxScrollExtent - 200) {
        pagination.fetchMore();
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Watch(
      builder: () {
        return ListView.builder(
          controller: _controller,
          itemCount: pagination.items.length,
          itemBuilder: (context, index) {
            final user = pagination.items[index];

            return ListTile(
              title: Text(user.name),
            );
          },
        );
      },
    );
  }
}

Unit Testing Example #

void main() {
  test('Reactive value updates correctly', () {
    final Reactive<int> counter = Reactive<int>(0);

    counter.value = 5;

    expect(counter.value, 5);
  });
}

Dependency Injection Example #

class ApiService {
  String get title => 'Reactive State';
}

void setupDependencies() {
  ReactiveInjector.singleton<ApiService>(
    () => ApiService(),
  );
}

final ApiService api = ReactiveInjector.find<ApiService>();

FAQ #

Does this use code generation? #

No. reactive_flutter works without generators or build_runner.


Does Watch rebuild the whole app? #

No.

Only widgets subscribed to changed reactive values rebuild.


Can I use it with existing architectures? #

Yes.

You can integrate it with:

  • Clean Architecture
  • MVVM
  • MVC
  • Feature-first architecture
  • Existing Provider/Riverpod/GetX apps

Does it support async state? #

Yes.

You can store Futures, async results, pagination state, and API responses inside reactive values.


Is it production ready? #

Yes.

The library is designed to be lightweight, predictable, and suitable for production applications.


Roadmap #

  • ❌ Computed reactive values
  • ❌ Reactive collections
  • ❌ DevTools integration
  • ❌ Async reactive helpers
  • ❌ Stream bindings
  • ❌ Form utilities
  • ❌ Persistent storage helpers
  • ❌ Flutter Web optimizations

Contributing #

Contributions are welcome.

Setup #

git clone <repository>
cd reactive_flutter
flutter pub get

Run Tests #

flutter test

Format Code #

dart format .

License #

MIT License

2
likes
0
points
14
downloads

Publisher

verified publishervdeveloper.tech

Weekly Downloads

A lightweight auto-tracking reactive state management library for Flutter.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter

More

Packages that depend on reactive_flutter