Skip to content

Commit

Permalink
Bug fixed on testing
Browse files Browse the repository at this point in the history
  • Loading branch information
JhonaCodes committed Mar 4, 2025
1 parent 5aa7dda commit f6699f5
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 21 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# 2.6.1
- Added mounted check in _valueChanged() method to prevent "setState() called after dispose()" errors when asynchronous notifications arrive after widget removal from the tree.

### 🐛 Bug Fixes
- where `ReactiveViewModelBuilder` could attempt to update no longer available widgets, causing runtime exceptions, especially during integration tests.
- Improved lifecycle management of listeners to prevent memory leaks and unexpected behaviors.


# 2.6.0
- Added new `ViewModel<T>` abstract class with robust lifecycle management, automatic reinitialization, and detailed diagnostic logging.
- Implemented `ReactiveNotifierViewModel<VM, T>` to better encapsulate ReactiveNotifier's singleton management with ViewModels.
Expand Down
31 changes: 10 additions & 21 deletions lib/src/builder/reactive_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ class ReactiveBuilder<T> extends StatefulWidget {
class _ReactiveBuilderState<T> extends State<ReactiveBuilder<T>> {
late T value;
final Map<String, _NoRebuildWrapper> _noRebuildWidgets = {};
Timer? debounceTimer;

@override
void initState() {
Expand All @@ -50,9 +49,6 @@ class _ReactiveBuilderState<T> extends State<ReactiveBuilder<T>> {
@override
void dispose() {
widget.notifier.removeListener(_valueChanged);
debounceTimer?.cancel();

debounceTimer?.cancel();

if (widget.notifier is ReactiveNotifier) {
final reactiveNotifier = widget.notifier as ReactiveNotifier;
Expand All @@ -66,13 +62,11 @@ class _ReactiveBuilderState<T> extends State<ReactiveBuilder<T>> {
}

void _valueChanged() {
// Cancel any existing timer to prevent multiple updates within the debounce period.
debounceTimer?.cancel();

// Start a new timer. After 100 milliseconds, update the state and rebuild the widget.
setState(() {
value = widget.notifier.notifier;
});
if(mounted) {
setState(() {
value = widget.notifier.notifier;
});
}
}

Widget _noRebuild(Widget keep) {
Expand Down Expand Up @@ -153,8 +147,6 @@ class _ReactiveBuilderStateViewModel<T>
/// Cache for widgets that shouldn't rebuild
final Map<String, _NoRebuildWrapperViewModel> _noRebuildWidgets = {};

/// Timer for debouncing updates
Timer? debounceTimer;

@override
void initState() {
Expand Down Expand Up @@ -213,17 +205,16 @@ class _ReactiveBuilderStateViewModel<T>
widget.notifier!.removeListener(_valueChanged);
}

debounceTimer?.cancel();
super.dispose();
}

/// Handles state changes from the notifier
void _valueChanged() {
// Cancel existing debounce timer
debounceTimer?.cancel();
setState(() {
value = widget.viewmodel?.data ?? widget.notifier!.data;
});
if(mounted) {
setState(() {
value = widget.viewmodel?.data ?? widget.notifier!.data;
});
}
}

/// Creates or retrieves a cached widget that shouldn't rebuild
Expand Down Expand Up @@ -271,5 +262,3 @@ class _NoRebuildWrapperStateViewModel
@override
Widget build(BuildContext context) => child;
}

bool get isTesting => const bool.fromEnvironment('dart.vm.product') == true;

0 comments on commit f6699f5

Please sign in to comment.