minimal_mvn 2.0.1 copy "minimal_mvn: ^2.0.1" to clipboard
minimal_mvn: ^2.0.1 copied to clipboard

A minimal state management solution for Flutter apps using the Model-View-Notifier (MVN) pattern

Minimal Logo

Pub Version License

Minimal MVN #

A minimal state management package for Flutter. Part of a minimalistic architecture based on the MVN (Model-View-Notifier) pattern.

This package aims for the simplest possible architecture, making it easier to understand and use, while offering an alternative to the growing complexity found in many other state management solutions, in an attempt to minimize side effects.

Try it #

Check out the live example at https://alesalv.github.io/minimal/

Counter

The classical Flutter counter app demonstrates basic state management. The counter on the top is a non disposable notifier, so it keeps memory when re-entering the page. The one on the bottom is a disposable notifier, so it resets when re-entering the page.

Chroma Counter

A more advanced counter widget, which increases the counter, and randomly changes color and shape. The reveal button shows a second widget using the same notifier. Thanks to the autodispose feature, the notifier is disposed only when both the widgets are not visible anymore. The string on top of the choma counter updates every 10 counts, thanks to the select feature, which is used to avoid unnecessary rebuilds.

The complete source code is in the example folder.

Getting Started #

Add Minimal to your pubspec.yaml:

dart pub add minimal_mvn
# or
flutter pub add minimal_mvn
copied to clipboard

and import the package:

import 'package:minimal_mvn/minimal_mvn.dart';
copied to clipboard

You can now start using Minimal's MVN pattern in your application. The quickest way is to follow the 4 steps below.

Features #

  • 🎯 MVN (Model-View-Notifier) pattern
  • 🚀 Lazy initialization of notifiers
  • 🔄 Optional autodispose for notifiers
  • ⚡ State selection for optimized rebuilds
  • 📦 Dependency injection with locator

State Management in 4 Steps #

1. Create an immutable UI state #

@MappableClass()
class ChromaCounterUIState with ChromaCounterUIStateMappable {
  const ChromaCounterUIState({
    this.backgroundColor = Colors.blue,
    this.count = 0,
  });
  final Color backgroundColor;
  final int count;
}
copied to clipboard

2. Create a notifier to hold your state #

class ChromaCounterNotifier extends MMNotifier<ChromaCounterUIState> {
  ChromaCounterNotifier() : super(const ChromaCounterUIState());

  void nextMetamorph() => notify(
        state.copyWith(
          backgroundColor: _randomColor(),
          count: state.count + 1,
        ),
      );
}
copied to clipboard

3. Create a manager to access your notifier #

final MMManager<ChromaCounterNotifier> chromaCounterManager =
    MMManager(ChromaCounterNotifier.new, autodispose: true);
copied to clipboard

4 Use the notifier from UI #

Access the notifier upon user's actions
FloatingActionButton(
  onPressed: () => chromaCounterManager.notifier.nextMetamorph(),
);
copied to clipboard
Rebuild the UI when state changes
final notifier = chromaCounterManager.notifier;
return ListenableBuilder(
  listenable: notifier,
  builder: (context, _) => Container(
    color: notifier.state.backgroundColor,
    child: const Text('Count: ${notifier.state.count}'),
  ),
);
copied to clipboard
(Optimized) Rebuild the UI only when part of the state changes
final notifier = chromaCounterManager.notifier;
return ListenableBuilder(
  listenable: notifier.select((state) => state.backgroundColor),
  builder: (context, _) => Container(
    color: notifier.state.backgroundColor,
  ),
);
copied to clipboard

Testing #

Widget Testing #

In tests, you can override the notifier with a mock notifier through the minimal manager:

testWidgets('should update UI when state changes', (tester) async {
  // Use the minimal manager to override the notifier
  chromaCounterManager.override(MockCounterNotifier.new);

  await tester.pumpWidget(const MaterialApp(home: ChromaCounter()));

  // Change state through the mock notifier
  chromaCounterManager.notifier.nextMetamorph();
  await tester.pump();

  final newColor = _getContainerColor(tester);
  // Test the exact color instead of a random one
  expect(newColor, equals(Colors.red));
});
copied to clipboard

See the example app tests for more testing examples.

17
likes
160
points
400
downloads

Publisher

unverified uploader

Weekly Downloads

2024.08.30 - 2025.03.14

A minimal state management solution for Flutter apps using the Model-View-Notifier (MVN) pattern

Repository (GitHub)

Topics

#state-management #mvn #dependency-injection #architecture

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter

More

Packages that depend on minimal_mvn