Skip to content

Commit ba3cd81

Browse files
committed
Improve watch_it documentation consistency and structure
- Add backticks to all package names (get_it, watch_it, command_it, listen_it) for consistent code formatting across 11 documentation files - Remove redundant "Watch Functions Reference" from sidebar navigation - Simplify how_it_works.md to focus on concepts rather than implementation details - Streamline debugging_tracing.md by removing redundant sections - Add new code samples for debugging common errors and handler issues - Update WatchItSubTreeTraceControl documentation with proper usage examples
1 parent 2012456 commit ba3cd81

13 files changed

Lines changed: 397 additions & 286 deletions
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
// ignore_for_file: unused_local_variable, unused_element, unreachable_from_main
2+
import 'package:flutter/material.dart';
3+
import 'package:watch_it/watch_it.dart';
4+
import 'package:listen_it/listen_it.dart';
5+
import '_shared/stubs.dart';
6+
7+
final di = GetIt.instance;
8+
9+
// Simple classes for debugging examples
10+
class Manager {
11+
final data = ValueNotifier<String>('');
12+
}
13+
14+
typedef Todo = TodoModel;
15+
16+
// #region watch_outside_build_bad
17+
// BAD
18+
class WatchOutsideBuildBad extends WatchingWidget {
19+
WatchOutsideBuildBad() {
20+
final data = watchValue((Manager m) => m.data); // Wrong context!
21+
}
22+
23+
void onPressed() {
24+
final data = watchValue((Manager m) => m.data); // Wrong!
25+
}
26+
27+
@override
28+
Widget build(BuildContext context) {
29+
return Container();
30+
}
31+
}
32+
// #endregion watch_outside_build_bad
33+
34+
// #region watch_outside_build_good
35+
// GOOD
36+
class WatchOutsideBuildGood extends WatchingWidget {
37+
@override
38+
Widget build(BuildContext context) {
39+
final data = watchValue((Manager m) => m.data); // Correct!
40+
41+
return ElevatedButton(
42+
onPressed: () {
43+
doSomething(data); // Use the value
44+
},
45+
child: Text('$data'),
46+
);
47+
}
48+
}
49+
50+
void doSomething(String data) {}
51+
// #endregion watch_outside_build_good
52+
53+
// #region not_listenable_bad
54+
// BAD
55+
class TodoManagerNotListenable {
56+
// Not a Listenable!
57+
final todos = ValueNotifier<List<Todo>>([]);
58+
}
59+
60+
class NotListenableBad extends WatchingWidget {
61+
@override
62+
Widget build(BuildContext context) {
63+
// ignore: type_argument_not_matching_bounds
64+
final manager = watchIt<TodoManagerNotListenable>(); // ERROR!
65+
return Container();
66+
}
67+
}
68+
// #endregion not_listenable_bad
69+
70+
// #region not_listenable_good_watch_value
71+
// GOOD
72+
class NotListenableGoodWatchValue extends WatchingWidget {
73+
@override
74+
Widget build(BuildContext context) {
75+
final todos = watchValue((TodoManagerNotListenable m) => m.todos);
76+
return Container();
77+
}
78+
}
79+
// #endregion not_listenable_good_watch_value
80+
81+
// #region not_listenable_good_change_notifier
82+
// Also GOOD
83+
class TodoManagerListenable extends ChangeNotifier {
84+
List<Todo> _todos = [];
85+
86+
void addTodo(Todo todo) {
87+
_todos.add(todo);
88+
notifyListeners(); // Now it's a Listenable
89+
}
90+
}
91+
92+
class NotListenableGoodChangeNotifier extends WatchingWidget {
93+
@override
94+
Widget build(BuildContext context) {
95+
final manager = watchIt<TodoManagerListenable>(); // Works now!
96+
return Container();
97+
}
98+
}
99+
// #endregion not_listenable_good_change_notifier
100+
101+
// #region not_registered_solution
102+
void main() {
103+
// Register BEFORE runApp
104+
di.registerSingleton<TodoManager>(TodoManager(DataService(ApiClient())));
105+
106+
runApp(MyApp());
107+
}
108+
// #endregion not_registered_solution
109+
110+
// #region not_watching_bad
111+
class NotWatchingBad extends WatchingWidget {
112+
@override
113+
Widget build(BuildContext context) {
114+
// BAD - Not watching, just accessing
115+
final manager = di<TodoManager>();
116+
final todos = manager.todos.value; // No watch!
117+
return Container();
118+
}
119+
}
120+
// #endregion not_watching_bad
121+
122+
// #region not_watching_good
123+
class NotWatchingGood extends WatchingWidget {
124+
@override
125+
Widget build(BuildContext context) {
126+
// GOOD - Actually watching
127+
final todos = watchValue((TodoManager m) => m.todos);
128+
return Container();
129+
}
130+
}
131+
// #endregion not_watching_good
132+
133+
// #region not_notifying_bad
134+
// BAD - Changing value without notifying
135+
class TodoManagerNotNotifying {
136+
final todos = ValueNotifier<List<Todo>>([]);
137+
138+
void addTodo(Todo todo) {
139+
todos.value.add(todo); // Modifies list but doesn't notify!
140+
}
141+
}
142+
// #endregion not_notifying_bad
143+
144+
// #region not_notifying_good_list_notifier
145+
// GOOD - ListNotifier automatically notifies on mutations
146+
class TodoManagerListNotifier {
147+
final todos = ListNotifier<Todo>(data: []);
148+
149+
void addTodo(Todo todo) {
150+
todos.add(todo); // Automatically notifies listeners!
151+
}
152+
}
153+
// #endregion not_notifying_good_list_notifier
154+
155+
// #region not_notifying_good_custom_notifier
156+
// GOOD - Extend ValueNotifier and call notifyListeners
157+
class TodoManagerCustomNotifier extends ValueNotifier<List<Todo>> {
158+
TodoManagerCustomNotifier() : super([]);
159+
160+
void addTodo(Todo todo) {
161+
value.add(todo);
162+
notifyListeners(); // Manually trigger notification
163+
}
164+
}
165+
// #endregion not_notifying_good_custom_notifier
166+
167+
// #region memory_leak_bad
168+
// BAD - Manual subscriptions leak
169+
class MemoryLeakBad extends StatelessWidget {
170+
@override
171+
Widget build(BuildContext context) {
172+
final manager = di<Manager>();
173+
manager.data.addListener(() {
174+
// This leaks! No cleanup
175+
});
176+
return Container();
177+
}
178+
}
179+
// #endregion memory_leak_bad
180+
181+
// #region memory_leak_good
182+
// GOOD - Automatic cleanup
183+
class MemoryLeakGood extends WatchingWidget {
184+
@override
185+
Widget build(BuildContext context) {
186+
final data = watchValue((Manager m) => m.data);
187+
return Text('$data');
188+
}
189+
}
190+
// #endregion memory_leak_good
191+
192+
class MyApp extends StatelessWidget {
193+
@override
194+
Widget build(BuildContext context) => Container();
195+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// ignore_for_file: unused_local_variable, unused_element
2+
import 'package:flutter/material.dart';
3+
import 'package:watch_it/watch_it.dart';
4+
import 'package:command_it/command_it.dart';
5+
6+
// Manager with commands for handler examples
7+
class SaveManager {
8+
final saveCommand = Command.createAsyncNoParamNoResult(
9+
() async {
10+
await Future.delayed(const Duration(milliseconds: 500));
11+
},
12+
debugName: 'save',
13+
);
14+
15+
final isLoading = ValueNotifier<bool>(false);
16+
}
17+
18+
// #region handler_registered_after_return_bad
19+
// BAD - Handler registered AFTER early return
20+
class HandlerAfterReturnBad extends WatchingWidget {
21+
@override
22+
Widget build(BuildContext context) {
23+
final isLoading = watchValue((SaveManager m) => m.isLoading);
24+
25+
if (isLoading) {
26+
return CircularProgressIndicator(); // Returns early!
27+
}
28+
29+
// This handler never gets registered when loading!
30+
registerHandler(
31+
select: (SaveManager m) => m.saveCommand,
32+
handler: (context, result, cancel) {
33+
Navigator.pop(context);
34+
},
35+
);
36+
37+
return MyForm();
38+
}
39+
}
40+
// #endregion handler_registered_after_return_bad
41+
42+
// #region handler_registered_before_return_good
43+
// GOOD - Handler registered before conditional logic
44+
class HandlerBeforeReturnGood extends WatchingWidget {
45+
@override
46+
Widget build(BuildContext context) {
47+
registerHandler(
48+
select: (SaveManager m) => m.saveCommand,
49+
handler: (context, result, cancel) {
50+
Navigator.pop(context);
51+
},
52+
);
53+
54+
final isLoading = watchValue((SaveManager m) => m.isLoading);
55+
56+
if (isLoading) {
57+
return CircularProgressIndicator();
58+
}
59+
60+
return MyForm();
61+
}
62+
}
63+
// #endregion handler_registered_before_return_good
64+
65+
// Stub widgets
66+
class MyForm extends StatelessWidget {
67+
@override
68+
Widget build(BuildContext context) => Container();
69+
}

docs/.vitepress/config.mts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,7 @@ export default defineConfig({
7878
{ text: 'Accessing get_it Features', link: '/documentation/watch_it/advanced_integration.md' },
7979
{ text: 'Best Practices', link: '/documentation/watch_it/best_practices.md' },
8080
{ text: 'Debugging & Troubleshooting', link: '/documentation/watch_it/debugging_tracing.md' },
81-
{ text: 'How watch_it Works', link: '/documentation/watch_it/how_it_works.md' },
82-
{ text: 'Watch Functions Reference', link: '/documentation/watch_it/watch_functions.md' }
81+
{ text: 'How watch_it Works', link: '/documentation/watch_it/how_it_works.md' }
8382
]
8483
},
8584
{

docs/documentation/watch_it/advanced_integration.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# Accessing get_it Features
1+
# Accessing `get_it` Features
22

3-
This guide shows how to access get_it features from within `watch_it` widgets. For detailed explanations of each get_it feature, see the [get_it documentation](/documentation/get_it/getting_started.md).
3+
This guide shows how to access `get_it` features from within `watch_it` widgets. For detailed explanations of each `get_it` feature, see the [`get_it` documentation](/documentation/get_it/getting_started.md).
44

55
## Scopes with pushScope
66

7-
get_it scopes create temporary registrations that are automatically cleaned up. Perfect for screen-specific state. See [get_it Scopes](/documentation/get_it/scopes.md) for details.
7+
`get_it` scopes create temporary registrations that are automatically cleaned up. Perfect for screen-specific state. See [`get_it` Scopes](/documentation/get_it/scopes.md) for details.
88

99
### pushScope() - Automatic Scope Management
1010

@@ -24,7 +24,7 @@ get_it scopes create temporary registrations that are automatically cleaned up.
2424

2525
## Named Instances
2626

27-
Watch specific named instances from get_it. See [get_it Named Instances](/documentation/get_it/object_registration.md#named-instances) for registration details.
27+
Watch specific named instances from `get_it`. See [`get_it` Named Instances](/documentation/get_it/object_registration.md#named-instances) for registration details.
2828

2929
### Watching Named Instances
3030

@@ -37,7 +37,7 @@ Watch specific named instances from get_it. See [get_it Named Instances](/docume
3737

3838
## Async Initialization
3939

40-
Handle complex initialization where async dependencies must be ready before the app starts. See [get_it Async Objects](/documentation/get_it/async_objects.md) for registration details.
40+
Handle complex initialization where async dependencies must be ready before the app starts. See [`get_it` Async Objects](/documentation/get_it/async_objects.md) for registration details.
4141

4242
### isReady - Single Dependency
4343

@@ -57,7 +57,7 @@ Wait for all async dependencies to complete:
5757

5858
## See Also
5959

60-
- [get_it Scopes Documentation](/documentation/get_it/scopes.md)
61-
- [get_it Async Objects](/documentation/get_it/async_objects.md)
62-
- [get_it Named Instances](/documentation/get_it/object_registration.md#named-instances)
60+
- [`get_it` Scopes Documentation](/documentation/get_it/scopes.md)
61+
- [`get_it` Async Objects](/documentation/get_it/async_objects.md)
62+
- [`get_it` Named Instances](/documentation/get_it/object_registration.md#named-instances)
6363
- [Best Practices](/documentation/watch_it/best_practices.md)

0 commit comments

Comments
 (0)