Skip to content

Introduction ​

What is Flutter Compositions? ​

Flutter Compositions is a reactive framework for Flutter inspired by Vue's Composition API. It replaces StatefulWidget boilerplate with a declarative, signal-based programming model built on alien_signals.

At its core, you write a setup() method that runs once, declare reactive state with ref(), derive values with computed(), and return a builder function that automatically re-runs when dependencies change:

dart
class Counter extends CompositionWidget {
  const Counter({super.key});

  @override
  Widget Function(BuildContext) setup() {
    final count = ref(0);
    final doubled = computed(() => count.value * 2);

    return (context) => Column(
      children: [
        Text('Count: ${count.value}'),
        Text('Doubled: ${doubled.value}'),
        ElevatedButton(
          onPressed: () => count.value++,
          child: const Text('Increment'),
        ),
      ],
    );
  }
}

No State class. No setState(). No manual dispose(). Just reactive state and a builder.

Why Choose Flutter Compositions? ​

1. Fine-Grained Reactivity ​

Backed by alien_signals, reading .value registers dependencies automatically. Only the widgets that touch a modified ref rebuild — no unnecessary subtree reconstructions.

2. Vue-like Developer Experience ​

APIs (ref(), computed(), watch()) mirror the Vue Composition API, lowering the learning curve for frontend developers. setup() centralizes state initialization, computed values, and lifecycle hooks.

3. Lifecycle and Resource Management ​

FeatureWhat it does
onMounted / onUnmounted / onBuildDeclarative lifecycle hooks
useScrollController, useAnimationController, …Auto-dispose controllers
Effect cleanup via effectScopeNo forgotten subscriptions

4. Built-in Type-Safe Dependency Injection ​

InjectionKey<T> powers provide / inject — pass Ref<T> or any object while staying reactive and type-safe. Works out of the box, yet remains compatible with Riverpod, GetIt, and other DI solutions.

5. Hot Reload & State Preservation ​

Each Ref keeps a stable position inside setup(). As long as the declaration order stays intact, hot reload preserves state. Builders rely on reactive signals, so only affected areas refresh after a reload.

How Does It Compare? ​

vs. StatefulWidget ​

AspectStatefulWidgetFlutter Compositions
State declarationSeparate State classInline in setup()
RebuildssetState() rebuilds entire subtreeOnly refs that changed
Prop changesManual didUpdateWidgetAutomatic via widget()
ControllersManual dispose()Auto-disposed use* helpers

See the full migration guide.

vs. flutter_hooks ​

AspectFlutter Compositionsflutter_hooks
Mental modelVue Composition APIReact Hooks
ReactivityFine-grained signalsFull build re-run
DIBuilt-in provide/injectExternal packages
LifecycleonMounted, onUnmounteduseEffect callbacks

vs. Vue Composition API ​

AspectFlutter CompositionsVue
RenderingFlutter widget treeVirtual DOM / templates
Reactivity enginealien_signals (explicit refs)Proxy-based (deep by default)
Propswidget() returns ComputedRefProps are reactive proxies
DI keysInjectionKey<T> (compile-time safe)String/Symbol keys

When It Shines ​

  • You want a development model that feels like Vue Composition API.
  • Performance matters and you need to avoid unnecessary rebuilds.
  • Controllers, subscriptions, or effects must be consistently disposed.
  • You value type-safe dependency injection without extra packages.
  • The project targets multiple platforms but you want a unified reactive style.

When to Think Twice ​

  • The app is tiny and setState already covers your needs.
  • The team is deeply invested in flutter_hooks, BLoC, or Redux with heavy custom tooling.
  • You prefer external/global state managers to drive the entire app.

Next Steps ​

Released under the MIT License.