watch_it
Einfaches Zustandsmanagement, angetrieben durch get_it. Es ermöglicht das Beobachten von Änderungen von Objekten innerhalb des get_it-Dienstlokalisators und das entsprechende Neuzeichnen der Benutzeroberfläche.
flutter-it/watch_it open-source repository details.
^9.3.0^6.0.0{"sdk":"flutter"}{"sdk":"flutter"}^6.0.0Englischer Projektschnappschuss. Aktuelle Inhalte auf GitHub.
📚 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. No ValueListenableBuilder, no StreamBuilder, no FutureBuilder—just watch your data and your UI stays in sync.
One line instead of 12. No nesting, no boilerplate. Watch multiple values without builder hell.
Part of flutter_it — A construction set of independent packages. watch_it + get_it is the recommended foundation. Add command_it and listen_it when you need them.
setState, no widget tree nestingLearn more about the benefits →
Add to your pubspec.yaml:
dependencies:
watch_it: ^2.2.0
get_it: ^9.0.5 # Recommended - watch_it builds on get_it
import 'package:watch_it/watch_it.dart';
// 1. Create a model with ValueNotifier properties
class CounterModel {
final count = ValueNotifier<int>(0);
void increment() => count.value++;
}
// 2. Register with get_it (using exported 'di' instance)
di.registerSingleton(CounterModel());
// 3. Watch it - widget rebuilds automatically
class CounterWidget extends WatchingWidget {
@override
Widget build(BuildContext context) {
final count = watchValue((CounterModel m) => m.count);
return Column(
children: [
Text('$count'),
ElevatedButton(
onPressed: di<CounterModel>().increment,
child: Text('Increment'),
),
],
);
}
}
That's it! No builders, no manual subscriptions. Just watch and rebuild.
Watch multiple values without nesting builders:
class UserDashboard extends WatchingWidget {
@override
Widget build(BuildContext context) {
// Watch multiple values - no nested builders!
final userName = watchValue((UserModel m) => m.name);
final isLoggedIn = watchValue((AuthModel m) => m.isLoggedIn);
final notifications = watchStream(
(NotificationModel m) => m.updates,
initialValue: []
);
if (!isLoggedIn) return LoginScreen();
return Text(
'$userName - ${notifications.data?.length ?? 0} notifications'
);
}
}
Replace Builders with simple one-line watch calls:
watchValue — Watch ValueListenable properties from get_it objects
watchIt — Watch whole Listenable objects registered in get_it
watchPropertyValue — Watch specific property, rebuilds only when value changes
watchStream — Reactive streams without StreamBuilder
watchFuture — Reactive futures without FutureBuilder
watch — Watch any local Listenable
Execute side effects without rebuilding:
registerHandler — React to ValueListenable changes (show dialogs, navigate)
registerStreamHandler — React to stream events
registerFutureHandler — React to future completion
registerChangeNotifierHandler — React to ChangeNotifier changes
If you have one manager per entity (e.g. per station id), register it with registerCachedFactoryParam and pass the parameter to the watch function. When the parameter changes, watch_it automatically unsubscribes from the old instance and subscribes to the new one:
di.registerCachedFactoryParam<StationManager, String, void>(
(stationId, _) => StationManager(stationId),
);
class StationTile extends WatchingWidget {
final String stationId;
const StationTile({super.key, required this.stationId});
@override
Widget build(BuildContext context) {
final name = watchValue((StationManager m) => m.name, param1: stationId);
return Text(name);
}
}
param1/param2 are available on all watch and handler functions that resolve their object from get_it. They are only valid for types registered with registerCachedFactoryParam. Plain registerFactory registrations can't be watched at all (every build would get a new instance) and are rejected in debug mode.
Powerful functions for StatelessWidgets:
createOnce — Create objects on first build, auto-dispose on widget destroy
callOnce — Execute function only on first build
callOnceAfterThisBuild — Execute function once after current build completes
callAfterEveryBuild — Execute function after every rebuild
pushScope — Automatic get_it scope management tied to widget lifecycle
All watch* calls must:
build() methodif wrapping watch calls)Why these rules? watch_it uses index-based retrieval similar to React Hooks. Changing the order breaks the mapping between calls and stored data.
Read the detailed explanation →
Choose the widget type that fits your needs:
StatelessWidget, use for simple widgetsStatefulWidget, use when you need lifecycle or local stateStatelessWidget with with WatchItMixinStatefulWidget with with WatchItStatefulWidgetMixinBuilt on get_it — watch_it is designed to work with get_it's service locator pattern. Register your models, services, and business logic with get_it, then watch them reactively.
// Register with get_it
di.registerLazySingleton(() => UserManager());
di.registerLazySingleton(() => TodoManager());
// Watch them in any widget
class MyWidget extends WatchingWidget {
@override
Widget build(BuildContext context) {
final user = watchIt<UserManager>();
final todos = watchValue((TodoManager m) => m.todos);
return ListView(...);
}
}
Want more? Combine with other flutter_it packages:
get_it — Recommended pairing. Service locator for dependency injection. Access global services with di<T>().
Optional: command_it — Command pattern with loading/error states. Watch Commands reactively for automatic UI updates.
Optional: listen_it — ValueListenable operators (map, debounce, where). Watch reactive collections (ListNotifier, MapNotifier, SetNotifier).
💡 flutter_it is a construction set — watch_it + get_it is the recommended foundation. Add command_it and listen_it when you need advanced features. Each package works independently.
This package ships an Agent Skill for AI coding assistants
(Claude Code, Cursor, GitHub Copilot, Codex, Gemini CLI and others) in skills/watch-it-expert/.
It teaches them the critical rules, common patterns and anti-patterns of watch_it.
Install it into your project with the official Dart skills tool:
dart run skills@ get
dart run skills@ getonly looks at direct dependencies. If you use get_it through watch_it, addget_itto your pubspec as well to also getget-it-expert.
For the ecosystem-wide skills (architecture guidance, feed/data-source patterns, overview) and the skills of the other flutter_it packages run:
dart run skills@ add flutter-it/flutter_it
watchValue() with exampleswatchIt(), watchPropertyValue(), watch()createOnce(), callOnce(), disposalContributions are welcome! Please read the contributing guidelines before submitting PRs.
MIT License - see LICENSE file for details.
Part of the flutter_it ecosystem — Build reactive Flutter apps the easy way. No codegen, no boilerplate, just code.