Skip to content
Frontend
Skill

/watch-it-expert

Expert guidance on watch_it reactive widget state management for Flutter. Covers watch functions (watch, watchIt, watchValue, watchStream, watchFuture), handler registration (registerHandler, registerStreamHandler, registerFutureHandler), lifecycle functions (callOnce,

BOOST
From plugin
watch-it
1881 skill
Install
$ npx -y skills add flutter-it/watch_it --skill watch-it-expert --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/watch-it-expert

Context preview

The summary Claude sees to decide when to auto-load this skill.

Expert guidance on watch_it reactive widget state management for Flutter. Covers watch functions (watch, watchIt, watchValue, watchStream, watchFuture), handler registration (registerHandler, registerStreamHandler, registerFutureHandler), lifecycle functions (callOnce,

SKILL.md

watch-it-expert.SKILL.md
name: watch-it-expert
description: Expert guidance on watch_it reactive widget state management for Flutter. Covers watch functions (watch, watchIt, watchValue, watchStream, watchFuture), handler registration (registerHandler, registerStreamHandler, registerFutureHandler), lifecycle functions (callOnce, createOnce, onDispose), ordering rules, watching cached factories with parameters (param1/param2, per-entity managers), widget granularity, and startup orchestration. Use when building reactive widgets with watch_it, watching ValueListenables/Streams/Futures, or managing widget-scoped state.
metadata:
  author: flutter-it
  version: "1.0"

watch_it Expert - Reactive Widget State Management

**What**: Reactive widgets that auto-rebuild when ValueListenables/Listenables, Streams, or Futures change. Built on get_it. Provides `di` global alias for `GetIt.I`.

**Related skill**: registration/scopes/async-init details live in `get-it-expert`. `dart run skills@ get` only installs skills of *direct* dependencies, so add `get_it` to your pubspec as well, or run `dart run skills@ add flutter-it/flutter_it` to get all flutter_it skills.

CRITICAL RULES

  • **ORDERING**: All `watch*()`, `registerHandler*()`, `createOnce()`, `callOnce()` calls MUST execute in the same order on every build (like React Hooks)
  • **Widget type**: Must extend `WatchingWidget` / `WatchingStatefulWidget` or use `WatchItMixin` / `WatchItStatefulWidgetMixin`
  • **Never in callbacks**: Don't call watch functions inside builders, callbacks, or event handlers
  • `watchValue` selector MUST return a `ValueListenable<R>`, not a bare value
  • `createOnce` works in BOTH stateless and stateful widgets
  • NEVER watch a type registered with plain `registerFactory`/`registerFactoryParam` — throws `StateError` in debug (every build would get a new instance). Use `registerCachedFactory(Param)`, a singleton, or pass the instance via `target:` (v2.5.0+)
  • Passing `param1`/`param2` for a registration that doesn't take params (or combining them with `target:`) throws in debug (v2.5.0+)

Widget Types

**ALWAYS prefer `WatchingWidget` / `WatchingStatefulWidget`** for new code. Only use the mixin variants (`WatchItMixin` / `WatchItStatefulWidgetMixin`) when:

  • The widget needs **additional mixins** (e.g. `TickerProviderStateMixin`)
  • You're **adding watch_it to existing code** and don't want to change the base class
// ✅ DEFAULT - Use WatchingWidget for new stateless widgets
class MyWidget extends WatchingWidget {
  @override
  Widget build(BuildContext context) { ... }
}

// ✅ DEFAULT - Use WatchingStatefulWidget for new stateful widgets
class MyWidget extends WatchingStatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

// ⚠️ ONLY when you need extra mixins or are retrofitting existing code
class MyWidget extends StatelessWidget with WatchItMixin { ... }
class MyWidget extends StatefulWidget with WatchItStatefulWidgetMixin { ... }

Watch Functions

// watch() - Watch any Listenable you have a reference to (ChangeNotifier, ValueNotifier, etc.)
final manager = watch(myChangeNotifier);            // rebuilds on notifyListeners()
final value = watch(someValueNotifier).value;       // for ValueNotifiers, access .value

// watchIt() - Watch a Listenable registered in get_it (T MUST extend Listenable)
final manager = watchIt<UserManager>();            // rebuilds on any notification
final config = watchIt<Config>(instanceName: 'dev');

// watchValue() - Watch a ValueListenable PROPERTY from a get_it object
// IMPORTANT: T extends Object (NOT Listenable!) — works with ANY class registered in get_it
// IMPORTANT: The selector MUST return a ValueListenable, not a bare value
// Returns the unwrapped value directly (no need to call .value)
final userState = watchValue((UserManager x) => x.userState);    // x.userState is ValueNotifier<UserState>
final isRunning = watchValue((MyManager x) => x.loadCommand.isRunning);  // isRunning is ValueListenable<bool>
// This is the PREFERRED way to watch command properties on non-Listenable managers:
final isLoading = watchValue((AuthManager m) => m.loginCommand.isRunning);  // AuthManager is NOT a Listenable — works!

// watchPropertyValue() - Watch a non-ValueListenable property from a Listenable (T MUST extend Listenable)
// Rebuilds only when the selected value changes (equality check)
final name = watchPropertyValue((UserManager x) => x.userName);  // userName is a plain String on a ChangeNotifier
// Also supports local target:
final name = watchPropertyValue((MyNotifier x) => x.name, target: myLocalNotifier);

// watchStream() - Replace StreamBuilder
// With get_it select (T looked up from get_it, select extracts the Stream):
final snapshot = watchStream(
  (EventBus x) => x.onEvent<LoginEvent>(),
  initialValue: null,
);
// With target: + select: for objects NOT in get_it (select applied to target):
final snapshot = watchStream(
  (MyService x) => x.statusStream,
  target: myLocalService,
  initialValue: Status.idle,
);
// With target: only — when target IS the Stream itself (pass null as select):
final snapshot = watchStream<Stream<AppLocale>, AppLocale>(
  null,
  target: LocaleSettings.getLocaleStream(),
  initialValue: LocaleSettings.currentLocale,
);

// watchFuture() - Replace FutureBuilder
// With get_it select (T looked up from get_it, select extracts the Future):
final snapshot = watchFuture(
  (ApiClient x) => x.fetchConfig(),
  initialValue: defaultConfig,  // REQUIRED
);
// With target: + select: for objects NOT in get_it (select applied to target):
final snapshot = watchFuture(
  (MyService x) => x.loadData(),
  target: myLocalService,
  initialValue: null,
);
// With target: only — when target IS the Future itself (pass null as select):
final snapshot = watchFuture<Future<Config>, Config>(
  null,
  target: someExternalFuture,
  initialValue: defaultConfig,
);

Cached Factories with Parameters (v2.5.0+, requires get_it 9.3.0)

Read more
Ships withwatch-it

📚 Complete documentation available at flutter-it.dev Check out the comprehensive docs with detailed guides, examples, and best practices! The easiest state management for Flutter built on get_it Widgets automatically rebuild when data changes.

Get the whole plugin
Stats
188
Stars
18
Forks
Maintained
Maintenance
Dart
Language
MIT
License
1mo ago
Last commit
3y ago
Created
1d ago
Added

Repo: flutter-it/watch_it