Original README snapshot from the linked source repository. Visit the repository for the latest content.
data_widget
data_widget is a Flutter package that provides a simple wrapper for InheritedWidget, InheritedModel, InheritedNotifier, ValueNotifier, and ChangeNotifier.
Features
Data
A widget that holds a single data and allows its descendants to access the data and listen to changes.
Providing the data
Data.inherit(
data: 'Hello, World!',
child: const MyWidget(),
)
Getting the data
There are multiple ways to get the data:
Find and listen
This method will find the nearest Data<T> widget (in this case Data<String>).
Calling this method will register a listener that will be invoked when the data changes.
In other words, the widget will rebuild when the data changes. This will throw
an assertion error if the data is not found.
String data = Data.of<String>(context);
Optionally find and listen
This method is similar to Data.of<T>(BuildContext context), but will not throw an assertion error if the data is not found.
String? data = Data.maybeOf<String>(context);
Find
This method will find the nearest Data<T> widget (in this case Data<String>).
This will throw an assertion error if the data is not found.
This method does not register any listener so the widget will not rebuild when the data changes.
This is useful when you only need to read the data once (i.e. in onPressed callback, onTap callback, etc.).
String data = Data.find<String>(context);
Optionally find
This method is similar to Data.find<T>(BuildContext context), but will not throw an assertion error if the data is not found.
String? data = Data.maybeFind<String>(context);
Blocking the data
You can stop the data from being passed down to its descendants by wrapping the widget with Data.boundary
Data.boundary<MyService>(
child: const MyWidget(),
)
MultiData
A widget that holds multiple data and allows its descendants to access the data and listen to changes without having to nest multiple Data widgets.
Usually, when you need to pass multiple data to its descendants, you will have to nest multiple Data widgets.
Data.inherit(
data: 'Hello, World!',
child: Data.inherit(
data: 42,
child: Data.boundary<MyService>(
child: const MyWidget(),
),
),
)
With MultiData, you can pass multiple data without having to nest multiple Data widgets.
MultiData(
data: [
Data<String>('Hello, World!'),
Data(42),
Data.boundary<MyService>(),
],
Getting the data is similar to Data widget.
[!NOTE]
Providing type in the type param is optional but encouraged to avoid runtime errors due to type mismatch.
[!WARNING]
The order of the data must be the same as the order of the data provided.
Model
A widget that holds a single model and allows its descendants to access or change the value of the model.
Similar to Data but uses symbol as the key to identify the model. Mostly useful when getting same type data
within the same widget tree.
Data.inherit(
data: 'Hello, World!',
child: Data.inherit(
data: 'Another!',
child: const MyWidget(),
),
)
MultiModel(
data: [
Model(#myString, 'Hello, World!'),
Model(#myString2, 'Another!'),
],
child: const MyWidget(),
)
Providing a read-only model
Model.inherit(
#myString,
'Hello World',
child: const MyWidget(),
)
Providing a model
String myString = 'Hello World';
Model.inherit(
#myString,
myString,
child: const MyWidget(),
onChanged: (value) {
myString = value;
},
)
Getting the model
There are multiple ways to get the model, most of them are similar to Data widget.
String myString = Model.of<String>(context, #myString);
String? myString = Model.maybeOf<String>(context, #myString);
String myString = Model.find<String>(context, #myString);
String? myString = Model.maybeFind<String>(context, #myString);
Blocking the model
You can stop the model from being passed down to its descendants by wrapping the widget with ModelBoundary
ModelBoundary<MyService>(
#myService,
child: const MyWidget(),
)
MultiModel(
data: [
ModelBoundary<MyService>(#myService),
ModelBoundary<MyService>(#myService2),
],
child: const MyWidget(),
)
MultiModel
A widget that holds multiple models and allows its descendants to access or change the value of the model.
Similar to MultiData but uses symbol as the key to identify the model. Mostly useful when getting same type data
within the same widget tree.
MultiModel(
data: [
Model(#myString, 'Hello, World!'),
Model(#myString2, 'Another!'),
ModelBoundary<MyService>(#myService),
],
child: const MyWidget(),
)
Getting the model is similar to Model widget.
[!NOTE]
Providing type in the type param is optional but encouraged to avoid runtime errors due to type mismatch.
[!WARNING]
The order of the data must be the same as the order of the data provided.
MutableNotifier
When using List (or any mutable object) as the value for ValueNotifier, it will not notify the listeners when the list is mutated,
because the reference to the list is not changed. MutableNotifier solves this problem by providing a method
to mutate the list and notify the listeners.
MutableNotifier<List<int>> list = MutableNotifier([1, 2, 3]);
list.mutate((value) {
value.add(4);
});
You can also decide whether to notify the listeners or not.
MutableNotifier<List<int>> set = MutableNotifier([1, 2, 3]);
set.mutate((value) {
if (!value.contains(4)) {
value.add(4);
return true;
}
return false;
});
ValueNotifierUnmodifiableView
A wrapper for ValueNotifier that provides an unmodifiable view of the value.
ValueNotifier<String> valueNotifier = ValueNotifier('Hello, World!');
ValueListenable<String> castedNotifier = valueNotifier;
(castedNotifier as ValueNotifier<String>).value = 'Another!';
ValueListenable<String> valueListenable = ValueNotifierUnmodifiableView(valueNotifier);
(valueListenable as ValueNotifier<String>).value = 'Another!';
You can also use the ValueNotifier extension method to convert the ValueNotifier to ValueNotifierUnmodifiableView.
ValueNotifier<String> _valueNotifier = ValueNotifier('Hello, World!');
ValueListenable<String> get valueListenable => _valueNotifier.readOnly();
ValueChangeNotifier
Similar to ValueNotifier, but listeners can be notified with the old value and the new value.
ValueChangeNotifier<int> valueChangeNotifier = ValueChangeNotifier(42);
valueChangeNotifier.addChangeListener((newValue, oldValue) {
print('Old value: $oldValue');
print('New value: $newValue');
});
valueChangeNotifier.value = 43;
ListNotifier
A list that can notify the listeners when the list is mutated.
ListNotifier<int> listNotifier = ListNotifier([1, 2, 3]);
listNotifier.addChangeListener((details) {
print('Added: ${details.added}');
print('Removed: ${details.removed}');
print('Index: ${details.index}');
});
listNotifier.add(4);
SetNotifier
A set that can notify the listeners when the set is mutated.
SetNotifier<int> setNotifier = SetNotifier({1, 2, 3});
setNotifier.addChangeListener((details) {
print('Added: ${details.added}');
print('Removed: ${details.removed}');
});
setNotifier.add(4);
MapNotifier
A map that can notify the listeners when the map is mutated.
MapNotifier<int, String> mapNotifier = MapNotifier({1: 'One', 2: 'Two', 3: 'Three'});
mapNotifier.addChangeListener((details) {
print('Added: ${details.added}');
print('Removed: ${details.removed}');
});
mapNotifier[4] = 'Four';
DebounceController
A controller that can be used to debounce the function call.
DebounceController debounceController = DebounceController();
debounceController.debounce(() {
print('Debounced!');
}, duration: const Duration(seconds: 1));
debounceController.debounce(() {
print('Debounced 2!');
}, duration: const Duration(seconds: 1));
await Future.delayed(const Duration(seconds: 1));
debounceController.debounce(() {
print('Debounced 3!');
}, duration: const Duration(seconds: 1));
Use case
Preventing multiple function calls when the user is typing in the search bar.
TextField(
onChanged: (value) {
debounceController.debounce(() {
}, duration: const Duration(milliseconds: 500));
},
)
Getting started
1. Install the package
In your terminal:
flutter pub add data_widget
or you can add it manually in your pubspec.yaml:
dependencies:
data_widget: {latest_version}
2. Import the package
import 'package:data_widget/data_widget.dart';
Using Experimental Version
If you want to use the experimental version, you can add the following to your pubspec.yaml:
dependencies:
data_widget:
git:
url: "https://github.com/sunarya-thito/data_widget.git"