Viewing version 0.5.0. Open the latest package page.

state_notifier

0.5.0

ValueNotifier, but outside Flutter and with some extra perks

Download archive

Readme

pub package Welcome to state_notifier~

This repository is a set of packages that reimplements ValueNotifier outside of Flutter.

It is spread across two packages:

  • state_notifier, a pure Dart package containing the reimplementation of ValueNotifier.
    It comes with extra utilities for combining our "ValueNotifier" with provider and to test it.
  • flutter_notifier, a binding between state_notifier and Flutter.
    It adds things like ChangeNotifierProvider from provider, but compatible with state_notifier.

Motivation

Extracting ValueNotifier outside of Flutter in a separate package has two purposes:

  • It allows Dart packages with no dependency on Flutter to use these classes.
    This means that we can use them on AngularDart for example.
  • It allows solving some common problems with the original ChangeNotifier/ValueNotifier and/or their combination with provider.

For example, by using state_notifier instead of the original ValueNotifier, then you get:

  • A significant simplification of the integration with provider
  • Simplified testing/mocking
  • Improved performances on addListener & notifyListeners equivalents.
  • Extra safety through small API changes

Integration with provider/service locators

StateNotifier is easily compatible with provider through an extra mixin: LocatorMixin.

Consider a typical StateNotifier written like a ValueNotifier:

class Counter extends StateNotifier<int> {
  Counter(): super(0)

  void increment() {
    state++;
  }
}

In this example, we may want to use Provider.of/context.read to connect our Counter with external services.

To do so, simply mix-in LocatorMixin as such:

class Counter extends StateNotifier<int> with LocatorMixin {
// unchanged
}

This then gives you access to:

  • read, a function to obtain services
  • update, a new life-cycle that can be used to listen to changes on a service

We could use them to change our Counter incrementation to save the counter in a DB when incrementing the value:

class Counter extends StateNotifier<int> {
  Counter(): super(0)

  void increment() {
    state++;
    read<LocalStorage>().writeInt('count', state);
  }
}

Testing

When using LocatorMixin, you may want to mock a dependency for your tests.
Of course, we still don't want to depend on Flutter/provider to do such a thing.

Similarly, since state is protected, tests need a simple way to read the state.

As such, LocatorMixin also adds extra utilities to help you with this scenario:

myStateNotifier.debugMockDependency<MyDependency>(myDependency);
print(myStateNotifier.debugState);
myStateNotifier.debugUpdate();

As such, if we want to test our previous Counter, we could mock LocalStorage this way:

test('increment and saves to local storage', () {
  final mockLocalStorage = MockLocalStorage();
  final counter = Counter()
    ..debugMockDependency<LocalStorage>(mockLocalStorage);

  expect(counter.debugState, 0);

  counter.increment(); // works fine since we mocked the LocalStorage

  expect(counter.debugState, 1);
  // mockito stuff
  verify(mockLocalStorage.writeInt('int', 1));
});

Differences with ValueNotifier

This is not a one-to-one reimplementation of ValueNotifier. It has some differences:

  • ValueNotifier is instead named StateNotifier (to avoid name clash)
  • ValueNotifier.value is renamed to state, to match the class name
  • StateNotifier is abstract
  • state is @protected
  • The listener passed to addListener receives the current state, and is called synchronously on addition.
  • addListener and removeListener are fused in a single addListener function which returns a function to remove the listener.
    This makes adding and removing listeners O(1) versus O(N) for ValueNotifier.
  • listeners cannot add extra listeners.
    This makes notifying listeners O(N) versus O(N²) for ValueNotifier
  • offers a mounted boolean to know if the StateNotifier was disposed or not, similar to State.
Changelog

[0.5.0] - 4/06/2020

If no onError is specified, errors are now reported to the current Zone.

[0.4.0] - 13/03/2020

Added a flag on addListener to disable the first immediate call of the listener thanks to @smiLLe

[0.3.0] - 08/03/2020

Add an initState life-cycle to be able to init the StateNotifier using read.

[0.1.0+1] - 06/03/2020

Add example

[0.1.0] - 06/03/2020

Initial release.

Installing

export PUB_HOSTED_URL=https://pub.mirror.p-hatan.ir
flutter pub add 'state_notifier:0.5.0'
pubspec.yaml
name: state_notifier
description: ValueNotifier, but outside Flutter and with some extra perks
version: 0.5.0
author: Remi Rousselet <darky12s@gmail.com>
homepage: https://github.com/rrousselGit/state_notifier

environment:
  sdk: ">=2.1.0 <3.0.0"

dependencies:
  meta: ^1.1.8

dev_dependencies:
  test: ^1.12.0
  mockito: ^4.1.1
  matcher: ^0.12.6

Version history

VersionPublishedArchiveSHA-256
0.1.0Cached · Upstream SHA-256 matchedDownload8c60803f…6789b4
0.1.0+1Cached · Upstream SHA-256 matchedDownload1ed2b17b…c3c33a
0.3.0Cached · Upstream SHA-256 matchedDownloadd4cfb50d…d92353
0.4.0Cached · Upstream SHA-256 matchedDownload0834beac…80ff69
0.5.0Cached · Upstream SHA-256 matchedDownload70c638d9…239200
0.6.0Cached · Upstream SHA-256 matchedDownload2cf1a0b8…105e39
0.7.0-nullsafety.0Cached · Upstream SHA-256 matchedDownload0615c755…7224db
0.7.0Cached · Upstream SHA-256 matchedDownload629c1053…e9054a
0.7.1Cached · Upstream SHA-256 matchedDownload46d90938…e507bf
0.7.2Cached · Upstream SHA-256 matchedDownloadbb2227ae…18bc0c
0.7.2+1Cached · Upstream SHA-256 matchedDownload8fe42610…aed289
1.0.0Cached · Upstream SHA-256 matchedDownloadb8677376…ba29bb

Dependencies

meta "^1.1.8"