You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Release v2.1.0 - Better error messages and documentation
- Improved error messages for watch ordering violations with clear guidance
- Added comprehensive watch ordering documentation to README
- Increased test coverage to 93.3%
Copy file name to clipboardExpand all lines: CHANGELOG.md
+7Lines changed: 7 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,3 +1,10 @@
1
+
## 2.1.0
2
+
3
+
### Improvements
4
+
***Better Error Messages**: Watch ordering violations now show a helpful error message instead of cryptic type errors. When conditional watch calls are placed incorrectly, you'll see clear guidance on how to fix it with BAD/GOOD examples.
5
+
***Enhanced Documentation**: Added "Watch Ordering and Conditional Watches" section to README with visual examples explaining why conditional watches must be at the end of build methods.
6
+
***Improved Test Coverage**: Test coverage increased to 93.3%.
Copy file name to clipboardExpand all lines: README.md
+87Lines changed: 87 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -239,6 +239,93 @@ There are some important rules to follow in order to avoid bugs with the `watch`
239
239
240
240
If you want to know more about the reasons for this rule check out [Lifting the magic curtain](#lifting-the-magic-curtain)
241
241
242
+
## Watch Ordering and Conditional Watches
243
+
244
+
The most common mistake when using WatchIt is placing conditional `watch` calls in the middle of your build method. **All `watch` calls must happen in the same order on every build.**
245
+
246
+
### The Problem
247
+
248
+
When you have conditional `watch` calls that come before other `watch` calls, WatchIt can lose track of which watch corresponds to which data. This happens because watches are stored in a list indexed by their call order.
249
+
250
+
**❌ BAD - Conditional in the middle:**
251
+
252
+
```dart
253
+
class MyWidget extends StatelessWidget with WatchItMixin {
254
+
@override
255
+
Widget build(BuildContext context) {
256
+
final listing = watchIt<Listing>();
257
+
258
+
// Conditional watch BEFORE other watches
259
+
if (listing.hasDetails) {
260
+
watch(listing.details!); // ❌ This is at index 1 SOMETIMES
261
+
}
262
+
263
+
// These watches will have different indices depending on the conditional
264
+
final count = watchValue((Model m) => m.count); // Index 1 or 2?
265
+
final name = watchValue((Model m) => m.name); // Index 2 or 3?
266
+
267
+
return Text('$count - $name');
268
+
}
269
+
}
270
+
```
271
+
272
+
When `listing.hasDetails` changes from `true` to `false`, the indices shift and WatchIt tries to retrieve the wrong watch entries. You'll see a helpful error message:
273
+
274
+
```
275
+
Watch ordering violation detected!
276
+
277
+
You have conditional watch calls (inside if/switch statements) that are
278
+
causing watch_it to retrieve the wrong objects on rebuild.
279
+
280
+
Fix: Move ALL conditional watch calls to the END of your build method.
281
+
Only the LAST watch call can be conditional.
282
+
283
+
Example - BAD:
284
+
watch(model);
285
+
if (condition) { watch(optional); } // ← Problem!
286
+
watchValue((M m) => m.property); // ← Gets wrong type
287
+
288
+
Example - GOOD:
289
+
watch(model);
290
+
watchValue((M m) => m.property);
291
+
if (condition) { watch(optional); } // ← At the end: OK
292
+
293
+
Widget: MyWidget
294
+
```
295
+
296
+
### The Solution
297
+
298
+
**✅ GOOD - Conditional at the end:**
299
+
300
+
```dart
301
+
class MyWidget extends StatelessWidget with WatchItMixin {
302
+
@override
303
+
Widget build(BuildContext context) {
304
+
final listing = watchIt<Listing>();
305
+
306
+
// All non-conditional watches FIRST
307
+
final count = watchValue((Model m) => m.count); // Always index 1
308
+
final name = watchValue((Model m) => m.name); // Always index 2
309
+
310
+
// Conditional watch at the END
311
+
if (listing.hasDetails) {
312
+
watch(listing.details!); // ✅ Only the last watch can be conditional
313
+
}
314
+
315
+
return Text('$count - $name');
316
+
}
317
+
}
318
+
```
319
+
320
+
When the conditional watch is at the end, adding or removing it doesn't affect the indices of previous watches.
321
+
322
+
### Key Takeaways
323
+
324
+
- ✅ **All non-conditional watches first**: Put regular `watch` calls at the top of your build method
325
+
- ✅ **Conditionals at the end**: Only the LAST watch call can be inside an `if`/`switch` statement
326
+
- ✅ **Same order every build**: Each `watch` call must happen at the same position on every build
327
+
- ❌ **No conditionals in the middle**: Don't put `watch` calls inside conditionals if other watches follow them
Copy file name to clipboardExpand all lines: pubspec.yaml
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
name: watch_it
2
2
description: The simple state management powered by get_it. It allows to observe changes of objects inside the get_it service locator and rebuild the UI accordingly.
0 commit comments