Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/robsonsilv4/flutter_value_notifier
Flutter Widgets that make it easy to implement state management patterns.
https://github.com/robsonsilv4/flutter_value_notifier
dart dartlang flutter flutter-package library provider state state-management valuenotifier widgets
Last synced: about 19 hours ago
JSON representation
Flutter Widgets that make it easy to implement state management patterns.
- Host: GitHub
- URL: https://github.com/robsonsilv4/flutter_value_notifier
- Owner: robsonsilv4
- License: mit
- Created: 2022-12-25T13:52:15.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2024-09-19T02:18:59.000Z (7 days ago)
- Last Synced: 2024-09-19T02:57:41.377Z (6 days ago)
- Topics: dart, dartlang, flutter, flutter-package, library, provider, state, state-management, valuenotifier, widgets
- Language: Dart
- Homepage: https://pub.dev/packages/flutter_value_notifier
- Size: 386 KB
- Stars: 4
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
---
Widgets that make it easy to use [ValueNotifier](https://api.flutter.dev/flutter/foundation/ValueNotifier-class.html) and helps to implement state management patterns in Flutter. Heavily inspired by [package:flutter_bloc](https://pub.dev/packages/flutter_bloc).
## Usage
Lets take a look at how to use `ValueNotifierProvider` to provide a `CounterNotifier` to a `CounterPage` and react to value changes with `ValueNotifierBuilder`.
### counter_notifier.dart
```dart
class CounterNotifier extends ValueNotifier {
CounterNotifier() : super(0);void increment() => value = value + 1;
void decrement() => value = value - 1;
}
```### main.dart
```dart
void main() => runApp(CounterApp());class CounterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: ValueNotifierProvider(
create: (_) => CounterNotifier(),
child: CounterPage(),
),
);
}
}
```### counter_page.dart
```dart
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: ValueNotifierBuilder(
builder: (_, count) => Center(child: Text('$count')),
),
floatingActionButton: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () => context.read().increment(),
),
const SizedBox(height: 4),
FloatingActionButton(
child: const Icon(Icons.remove),
onPressed: () => context.read().decrement(),
),
],
),
);
}
}
```At this point we have successfully separated our presentational layer from our business logic layer. Notice that the `CounterPage` widget knows nothing about what happens when a user taps the buttons. The widget simply notifies the `CounterNotifier` that the user has pressed either the increment or decrement button.
## ValueNotifier Widgets
### ValueNotifierProvider
**ValueNotifierProvider** is a Flutter widget which provides a notifier to its children via `ValueNotifierProvider.of(context)`. It is used as a dependency injection (DI) widget so that a single instance of a notifier can be provided to multiple widgets within a subtree.
In most cases, `ValueNotifierProvider` should be used to create new notifiers which will be made available to the rest of the subtree. In this case, since `ValueNotifierProvider` is responsible for creating the notifier, it will automatically handle closing it.
```dart
ValueNotifierProvider(
create: (_) => NotifierA(),
child: ChildA(),
);
```By default, ValueNotifierProvider will create the notifier lazily, meaning `create` will get executed when the notifier is looked up via `ValueNotifierProvider.of(context)`.
To override this behavior and force `create` to be run immediately, `lazy` can be set to `false`.
```dart
ValueNotifierProvider(
lazy: false,
create: (_) => NotifierA(),
child: ChildA(),
);
```In some cases, `ValueNotifierProvider` can be used to provide an existing notifier to a new portion of the widget tree. This will be most commonly used when an existing `notifier` needs to be made available to a new route. In this case, `ValueNotifierProvider` will not automatically close the notifier since it did not create it.
```dart
ValueNotifierProvider.value(
value: ValueNotifierProvider.of(context),
child: ScreenA(),
);
```then from either `ChildA`, or `ScreenA` we can retrieve `NotifierA` with:
```dart
// with extensions
context.read();// without extensions
ValueNotifierProvider.of(context);
```The above snippets result in a one time lookup and the widget will not be notified of changes. To retrieve the instance and subscribe to subsequent value changes use:
```dart
// with extensions
context.watch();// without extensions
ValueNotifierProvider.of(context, listen: true);
```In addition, `context.select` can be used to retrieve part of a value and react to changes only when the selected part changes.
```dart
final isPositive = context.select((notifier) => notifier.value >= 0);
```The snippet above will only rebuild if the value of the `CounterNotifier` changes from positive to negative or vice versa and is functionally identical to using a `ValueNotifierSelector`.
### MultiValueNotifierProvider
**MultiValueNotifierProvider** is a Flutter widget that merges multiple `ValueNotifierProvider` widgets into one.
`MultiValueNotifierProvider` improves the readability and eliminates the need to nest multiple `ValueNotifierProviders`.
By using `MultiValueNotifierProvider` we can go from:```dart
ValueNotifierProvider(
create: (_) => NotifierA(),
child: ValueNotifierProvider(
create: (_) => NotifierB(),
child: ValueNotifierProvider(
create: (_) => NotifierC(),
child: ChildA(),
)
)
)
```to:
```dart
MultiValueNotifierProvider(
providers: [
ValueNotifierProvider(
create: (_) => NotifierA(),
),
ValueNotifierProvider(
create: (_) => NotifierB(),
),
ValueNotifierProvider(
create: (_) => NotifierC(),
),
],
child: ChildA(),
)
```### ValueNotifierBuilder
**ValueNotifierBuilder** is a Flutter widget which requires a `ValueNotifier` and a `builder` function. `ValueNotifierBuilder` handles building the widget in response to new values. `ValueNotifierBuilder` is very similar to `ValueListenableBuilder` but has a more simple API to reduce the amount of boilerplate code needed. The `builder` function will potentially be called many times and should be a [pure function](https://en.wikipedia.org/wiki/Pure_function) that returns a widget in response to the value.
See `ValueNotifierListener` if you want to "do" anything in response to value changes such as navigation, showing a dialog, etc...
If the `notifier` parameter is omitted, `ValueNotifierBuilder` will automatically perform a lookup using `ValueNotifierProvider` and the current `BuildContext`.
```dart
ValueNotifierBuilder(
builder: (_, value) {
// return widget here based on NotifierA's value
}
)
```Only specify the notifier if you wish to provide a ValueNotifier that will be scoped to a single widget and isn't accessible via a parent `ValueNotifierProvider` and the current `BuildContext`.
```dart
ValueNotifierBuilder(
notifier: notifier, // provide the local ValueNotifier instance
builder: (_, value) {
// return widget here based on NotifierA's value
}
)
```For fine-grained control over when the `builder` function is called an optional `buildWhen` can be provided. `buildWhen` takes the previous ValueNotifier value and current ValueNotifier value and returns a boolean. If `buildWhen` returns true, `builder` will be called with `value` and the widget will rebuild. If `buildWhen` returns false, `builder` will not be called with `value` and no rebuild will occur.
```dart
ValueNotifierBuilder(
buildWhen: (previousValue, value) {
// return true/false to determine whether or not
// to rebuild the widget with value
},
builder: (_, value) {
// return widget here based on NotifierA's value
}
)
```### ValueNotifierSelector
**ValueNotifierSelector** is a Flutter widget which is analogous to `ValueNotifierBuilder` but allows developers to filter updates by selecting a new value based on the current notifier value. Unnecessary builds are prevented if the selected value does not change. The selected value must be immutable in order for `ValueNotifierSelector` to accurately determine whether `builder` should be called again.
If the `notifier` parameter is omitted, `ValueNotifierSelector` will automatically perform a lookup using `ValueNotifierProvider` and the current `BuildContext`.
```dart
ValueNotifierSelector(
selector: (value) {
// return selected value based on the provided value.
},
builder: (_, value) {
// return widget here based on the selected value.
},
)
```### ValueNotifierListener
**ValueNotifierListener** is a Flutter widget which takes a `ValueNotifierWidgetListener` and an optional `notifier` and invokes the `listener` in response to value changes in the notifier. It should be used for functionality that needs to occur once per value change such as navigation, showing a `SnackBar`, showing a `Dialog`, etc...
`listener` is only called once for each value change (**NOT** including the initial value) unlike `builder` in `ValueNotifierBuilder` and is a `void` function.
If the notifier parameter is omitted, `ValueNotifierListener` will automatically perform a lookup using `ValueNotifierProvider` and the current `BuildContext`.
```dart
ValueNotifierListener(
listener: (context, value) {
// do stuff here based on NotifierA's value
},
child: Container(),
)
```Only specify the notifier if you wish to provide a notifier that is otherwise not accessible via `ValueNotifierProvider` and the current `BuildContext`.
```dart
ValueNotifierListener(
notifier: notifier,
listener: (context, value) {
// do stuff here based on NotifierA's value
}
)
```For fine-grained control over when the `listener` function is called an optional `listenWhen` can be provided. `listenWhen` takes the previous notifier value and current notifier value and returns a boolean. If `listenWhen` returns true, `listener` will be called with `value`. If `listenWhen` returns false, `listener` will not be called with `value`.
```dart
ValueNotifierListener(
listenWhen: (previousValue, value) {
// return true/false to determine whether or not
// to call listener with value
},
listener: (context, value) {
// do stuff here based on NotifierA's value
},
child: Container(),
)
```### MultiValueNotifierListener
**MultiValueNotifierListener** is a Flutter widget that merges multiple `ValueNotifierListener` widgets into one.
`MultiValueNotifierListener` improves the readability and eliminates the need to nest multiple `ValueNotifierListeners`.
By using `MultiValueNotifierListener` we can go from:```dart
ValueNotifierListener(
listener: (context, value) {},
child: ValueNotifierListener(
listener: (context, value) {},
child: ValueNotifierListener(
listener: (context, value) {},
child: ChildA(),
),
),
)
```to:
```dart
MultiValueNotifierListener(
listeners: [
ValueNotifierListener(
listener: (context, value) {},
),
ValueNotifierListener(
listener: (context, value) {},
),
ValueNotifierListener(
listener: (context, value) {},
),
],
child: ChildA(),
)
```### ValueNotifierConsumer
**ValueNotifierConsumer** exposes a `builder` and `listener` in order react to new values. `ValueNotifierConsumer` is analogous to a nested `ValueNotifierListener` and `ValueNotifierBuilder` but reduces the amount of boilerplate needed. `ValueNotifierConsumer` should only be used when it is necessary to both rebuild UI and execute other reactions to value changes in the `notifier`. `ValueNotifierConsumer` takes a required `ValueNotifierWidgetBuilder` and `ValueNotifierWidgetListener` and an optional `notifier`, `ValueNotifierBuilderCondition`, and `ValueNotifierListenerCondition`.
If the `notifier` parameter is omitted, `ValueNotifierConsumer` will automatically perform a lookup using
`ValueNotifierProvider` and the current `BuildContext`.```dart
ValueNotifierConsumer(
listener: (context, value) {
// do stuff here based on NotifierA's value
},
builder: (_, value) {
// return widget here based on NotifierA's value
}
)
```An optional `listenWhen` and `buildWhen` can be implemented for more granular control over when `listener` and `builder` are called. The `listenWhen` and `buildWhen` will be invoked on each `notifier` `value` change. They each take the previous `value` and current `value` and must return a `bool` which determines whether or not the `builder` and/or `listener` function will be invoked. The previous `value` will be initialized to the `value` of the `notifier` when the `ValueNotifierConsumer` is initialized. `listenWhen` and `buildWhen` are optional and if they aren't implemented, they will default to `true`.
```dart
ValueNotifierConsumer(
listenWhen: (previous, current) {
// return true/false to determine whether or not
// to invoke listener with value
},
listener: (context, value) {
// do stuff here based on NotifierA's value
},
buildWhen: (previous, current) {
// return true/false to determine whether or not
// to rebuild the widget with value
},
builder: (_, value) {
// return widget here based on NotifierA's value
}
)
```### DependencyProvider
**DependencyProvider** is a Flutter widget which provides a dependency to its children via `DependencyProvider.of(context)`. It is used as a dependency injection (DI) widget so that a single instance of a dependency can be provided to multiple widgets within a subtree. `ValueNotifierProvider` should be used to provide notifier whereas `DependencyProvider` should only be used for dependencies.
```dart
DependencyProvider(
create: (_) => DependencyA(),
child: ChildA(),
);
```then from `ChildA` we can retrieve the `Dependency` instance with:
```dart
// with extensions
context.read();// without extensions
DependencyProvider.of(context)
```### MultiDependencyProvider
**MultiDependencyProvider** is a Flutter widget that merges multiple `DependencyProvider` widgets into one.
`MultiDependencyProvider` improves the readability and eliminates the need to nest multiple `DependencyProvider`.
By using `MultiDependencyProvider` we can go from:```dart
DependencyProvider(
create: (_) => DependencyA(),
child: DependencyProvider(
create: (_) => DependencyB(),
child: DependencyProvider(
create: (_) => DependencyC(),
child: ChildA(),
)
)
)
```to:
```dart
MultiDependencyProvider(
providers: [
DependencyProvider(
create: (_) => DependencyA(),
),
DependencyProvider(
create: (_) => DependencyB(),
),
DependencyProvider(
create: (_) => DependencyC(),
),
],
child: ChildA(),
)
```## Dart Versions
- Dart 2: >=2.19.0
- Flutter 3: >=3.0.0## Maintainers
- [@robsonsilv4 (Robson Silva)](https://github.com/robsonsilv4)
Thanks to [@felangel](https://github.com/felangel), [bloc library contributors](https://github.com/felangel/bloc/graphs/contributors) and [Icons8](https://icons8.com) by [Electricity](https://icons8.com/icon/0p9q9Fp5U2bz/electricity) icon.