Advanced Reactivity
This page builds on the basics from Reactivity Fundamentals and covers patterns you will encounter in real-world apps.
Combine Multiple Refs
Use computed when a value depends on more than one ref. Keep computations pure—no side effects.
final firstName = ref('');
final lastName = ref('');
final displayName = computed(() {
if (firstName.value.isEmpty && lastName.value.isEmpty) {
return 'Anonymous';
}
return '${firstName.value} ${lastName.value}'.trim();
});Memoize Expensive Work
Wrap heavy operations (sorting, filtering, formatting) in computed so they only re-run when needed.
final todos = ref(<Todo>[]);
final overdue = computed(() {
final now = DateTime.now();
return todos.value.where((t) => t.dueDate.isBefore(now)).toList();
});Watch Value Transitions
watch lets you observe how a value changes over time.
watch(() => cart.total.value, (total, previous) {
if (total > previous) {
analytics.trackCartChange(total);
}
});- Always provide a
previousparameter to compare old and new values. - The watcher cleans itself up when the widget unmounts.
React to Props
widget<T>() exposes the current widget instance as a ComputedRef<T> so you can observe prop changes.
@override
Widget Function(BuildContext) setup() {
final props = widget<UserAvatar>();
watch(() => props.value.userId, cache.loadAvatar);
// ...
}Imperative Context Access
Need BuildContext inside lifecycle hooks? Use useContext().
final contextRef = useContext();
onMounted(() {
final overlay = Overlay.of(contextRef.value!);
// ...
});contextRef.value stays null until the widget mounts, so guard against that in setup().
Batched Updates
Multiple writes inside the same microtask collapse into a single builder re-run.
void incrementTwice() {
count.value++;
count.value++;
}If you need intermediate frames, schedule them explicitly with Future.microtask or SchedulerBinding.
Debugging Tips
- Use
debugPrintinsidewatchEffectto trace when it re-runs. - Keep an eye out for
ref.value = ref.valuepatterns—they trigger unnecessary updates. - When the UI does not update, check that you read
.valueinside the builder or computation.
Next Steps
- Dive deep into the internals in Reactivity In Depth.
- Explore how
ComputedBuilderoptimizes rebuilds in the official API docs.