kaeru 0.1.3 copy "kaeru: ^0.1.3" to clipboard
kaeru: ^0.1.3 copied to clipboard

A powerful a comprehensive and efficient reactivity system for Flutter, inspired by Vue 3's @vue/reactivity.

Kaeru for Flutter #

Kaeru is a comprehensive and efficient reactivity system for Flutter, inspired by Vue 3's @vue/reactivity. It provides a fully functional reactive programming model that makes state management in Flutter simple, optimized, and declarative.

🚀 Features #

  • Fully reactive state management with Ref, Computed, AsyncComputed, and watchEffect.
  • Automatic dependency tracking for efficient updates.
  • Supports both synchronous and asynchronous computed values.
  • Optimized UI updates with Watch and KaeruMixin.
  • Seamless integration with ChangeNotifier and ValueNotifier.

📦 Installation #

Add this package to your pubspec.yaml:

dependencies:
  kaeru:
    git:
      url: https://github.com/tachibana-shin/flutter-kaeru.git

Import it in your project:

import 'package:kaeru/kaeru.dart';

🏗 API Documentation #

1️⃣ Reactive State: Ref<T> #

Represents a reactive variable that automatically triggers updates when changed.

Parameters:

Parameter Type Description
value T The initial value of the reactive reference.

Methods:

Method Returns Description
select<U>(U Function(T value)) Computed<U> Creates a computed value derived from this Ref<T>.

Example:

final count = Ref(0);
count.addListener(() {
  print("Count changed: ${count.value}");
});

count.value++;  // ✅ Triggers update

final doubleCount = count.select((v) => v * 2);
print(doubleCount.value); // ✅ 0
count.value = 5;
print(doubleCount.value); // ✅ 10

2️⃣ Derived State: Computed<T> #

Creates a computed value that automatically updates when dependencies change.

Parameters:

Parameter Type Description
getter T Function() A function that returns the computed value.

Methods:

Method Returns Description
select<U>(U Function(T value)) Computed<U> Creates a derived computed value.

Example:

final count = Ref(2);
final doubleCount = Computed(() => count.value * 2);

print(doubleCount.value); // ✅ 4
count.value++;
print(doubleCount.value); // ✅ 6

final tripleCount = doubleCount.select((v) => v * 1.5);
print(tripleCount.value); // ✅ 9

3️⃣ Effects: watchEffect & watch #

watchEffect(Function callback) -> VoidCallback

  • Automatically tracks dependencies and re-executes when values change.

Example:

final stop = watchEffect(() {
  print("Count is now: ${count.value}");
});

count.value++;  // ✅ Automatically tracks dependencies
stop(); // ✅ Stops watching

watch(List<ChangeNotifier> sources, Function callback, {bool immediate = false}) -> VoidCallback

  • Watches multiple ChangeNotifier sources.
  • If immediate = true, executes the callback immediately.

Example:

final stop = watch([count], () {
  print("Count changed: ${count.value}");
}, immediate: true);

stop(); // ✅ Stops watching

4️⃣ Asynchronous Derived State: AsyncComputed<T> #

Handles computed values that depend on asynchronous operations.

Parameters:

Parameter Type Description
getter Future<T> Function() A function returning a future value.
defaultValue T? An optional initial value before computation completes.
onError Function(dynamic error)? An optional error handler.
immediate bool Whether to compute immediately.

Example:

final asyncData = AsyncComputed(() async {
  await Future.delayed(Duration(seconds: 1));
  return "Loaded";
}, defaultValue: "Loading", onError: (e) => print("Error: $e"), immediate: true);

print(asyncData.value);  // ✅ "Loading"
await Future.delayed(Duration(seconds: 1));
print(asyncData.value);  // ✅ "Loaded"

5️⃣ UI Integration: KaeruMixin and Watch #

KaeruMixin (StatefulWidget Integration)

Allows stateful widgets to easily integrate with reactive values.

Example:

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> with KaeruMixin {
  late final Ref<int> count;

  @override
  void initState() {
    super.initState();
    count = ref(0);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Watch(() => Text("Count: ${count.value}")),
        ElevatedButton(
          onPressed: () => count.value++,
          child: Text("Increment"),
        ),
      ],
    );
  }
}

Watch (Automatic UI Rebuilds)

A widget that automatically updates when its dependencies change.

Example:

Watch(
  () => Text("Value: ${count.value}"),
)

6️⃣ Integration with ValueNotifier & ChangeNotifier #

ValueNotifier.toRef()

Converts a ValueNotifier<T> into a Ref<T>.

Example:

final valueNotifier = ValueNotifier(0);
final ref = valueNotifier.toRef();

ref.addListener(() {
  print("Updated: ${ref.value}");
});

valueNotifier.value = 10;  // ✅ Ref updates automatically

ValueNotifier Extension

Adds .toRef() to ValueNotifier to integrate seamlessly.


📌 Kaeru Lifecycle & Listening Mixins #

KaeruLifeMixin and KaeruListenMixin are powerful mixins designed to simplify Flutter development by providing Vue-like lifecycle hooks and reactive state listening.

🎯 Why Use These Mixins? #

✅ Cleaner code: No need to override multiple lifecycle methods or manage listeners manually. ✅ Reusable: Apply them to any StatefulWidget to enhance reactivity. ✅ Inspired by Vue: Provides a familiar development experience for reactive state management.

🟢 KaeruLifeMixin #

KaeruLifeMixin provides Vue-like lifecycle hooks for StatefulWidget. It enables multiple callbacks for different lifecycle events.

🚀 Features

  • onMounted(): Called when the widget is first created (initState).
  • onDependenciesChanged(): Called when dependencies change (didChangeDependencies).
  • onUpdated(): Called when the widget receives updated properties (didUpdateWidget).
  • onDeactivated(): Called when the widget is temporarily removed (deactivate).
  • onBeforeUnmount(): Called just before the widget is disposed (dispose).

📝 Example Usage

class MyComponent extends StatefulWidget {
  @override
  _MyComponentState createState() => _MyComponentState();
}

class _MyComponentState extends State<MyComponent> with KaeruLifeMixin<MyComponent> {
  @override
  void initState() {
    super.initState();

    onMounted(() => print('✅ Widget Mounted!'));
    onDependenciesChanged(() => print('🔄 Dependencies Changed!'));
    onUpdated(() => print('♻️ Widget Updated!'));
    onDeactivated(() => print('⚠️ Widget Deactivated!'));
    onBeforeUnmount(() => print('🗑 Widget Disposed!'));
  }

  @override
  Widget build(BuildContext context) {
    return Text('KaeruLifeMixin Example');
  }
}

🟢 KaeruListenMixin #

KaeruListenMixin simplifies listening to ChangeNotifier updates within a StatefulWidget. It allows adding listeners dynamically and managing their cleanup automatically.

🚀 Features

  • listen(): Subscribes to a single ChangeNotifier and executes a callback when it changes.
  • listenAll(): Subscribes to multiple ChangeNotifiers with a single callback.
  • Returns a cancel function to remove listeners when necessary.

📝 Example Usage

Listening to a Single Notifier
class MyNotifier extends ChangeNotifier {
  void update() {
    notifyListeners();
  }
}

class MyComponent extends StatefulWidget {
  @override
  _MyComponentState createState() => _MyComponentState();
}

class _MyComponentState extends State<MyComponent> with KaeruListenMixin<MyComponent> {
  final myNotifier = MyNotifier();
  VoidCallback? cancelListener;

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

    cancelListener = listen(myNotifier, () {
      print('Single notifier changed!');
    });
  }

  @override
  void dispose() {
    cancelListener?.call();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Text('Listening to a single ChangeNotifier');
  }
}
Listening to Multiple Notifiers
class NotifierA extends ChangeNotifier {
  void update() => notifyListeners();
}

class NotifierB extends ChangeNotifier {
  void update() => notifyListeners();
}

class MyComponent extends StatefulWidget {
  @override
  _MyComponentState createState() => _MyComponentState();
}

class _MyComponentState extends State<MyComponent> with KaeruListenMixin<MyComponent> {
  final notifierA = NotifierA();
  final notifierB = NotifierB();
  VoidCallback? cancelListeners;

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

    cancelListeners = listenAll([notifierA, notifierB], () {
      print('One of the notifiers changed!');
    });
  }

  @override
  void dispose() {
    cancelListeners?.call();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Text('Listening to multiple ChangeNotifiers');
  }
}

✨ Summary #

Feature KaeruLifeMixin KaeruListenMixin
Lifecycle Hooks ✅ Provides onMounted, onUpdated, onBeforeUnmount, etc. ❌ Not applicable
Reactive Listeners ❌ Not applicable ✅ Handles ChangeNotifier updates
Automatic Cleanup ✅ Hooks are executed at proper lifecycle stages ✅ Listeners are removed automatically
Code Simplicity ✅ Reduces the need for overriding multiple lifecycle methods ✅ Manages ChangeNotifier subscriptions easily

🚀 KaeruLifeMixin is perfect for handling widget lifecycle events. 🔄 KaeruListenMixin makes managing ChangeNotifier listeners easy.


🎯 API Summary #

Feature Supported
Ref<T>
Computed<T>
AsyncComputed<T>
watchEffect
watch
KaeruMixin
Watch Widget
ValueNotifier.toRef()
ReactiveNotifier<T>
VueNotifier.toRef()

This package provides an intuitive and efficient reactivity system for Flutter, making state management much easier and more performant. 🚀

🛠 Contributing #

Pull requests and feature requests are welcome! Feel free to open an issue or contribute.

📜 License #

MIT License. See LICENSE for details.

1
likes
0
points
56
downloads

Publisher

unverified uploader

Weekly Downloads

A powerful a comprehensive and efficient reactivity system for Flutter, inspired by Vue 3's @vue/reactivity.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, notifier_plus, plugin_platform_interface

More

Packages that depend on kaeru