Search the site
APP
Keep a value in a signal and the widget that reads it redraws when it changes.
Combine signals with + * > & and the result is a signal too.
ON THIS PAGE
Create a signal with context.signal
Set, update and read a signal
Derive signals with operators
Make a model reactive
Share one object with DV.global
Observe the app lifecycle
Status
Functional
Class
@DVPage(title: 'Cart')
Widget _cartPage(BuildContext context) {
final DVSignal<int> quantity = context.signal(1);
final DVSignal<int> price = context.signal(1200);
// Each of these is a signal that tracks its sources.
final total = price * quantity;
final inStock = quantity > 0;
return DVBox.list(<Widget>[
// Reading .value in build redraws this page when a source changes.
DVText('Total: ${total.value}'),
DVText(inStock.value ? 'Ready to order' : 'Add something first'),
DVText('Add one').modifier(
DVModifier().onTap(() => quantity.value = quantity.value + 1),
),
]);
}Copy code to clipboard
context.signal(initial) creates a DVSignal for this widget.
Reading .value in build subscribes the widget to it.
Signals match by call order in build, like hooks. Create them unconditionally.
signal(context, value) is the same call as a top-level function.
quantity.value = 3; // set
quantity.update((int n) => n + 1); // set from the current value
final int now = quantity.read(); // read without subscribingCopy code to clipboard
An operator on a signal returns a signal that tracks its sources. There is no separate computed type to learn.
final DVSignal<int> price = context.signal(1200);
final DVSignal<int> quantity = context.signal(2);
final DVSignal<bool> agreed = context.signal(false);
final DVSignal<bool> paid = context.signal(false);
final DVSignal<String> first = context.signal('Ada');
final subtotal = price * quantity; // + - * / ~/ % on numbers
final expensive = subtotal >= 10000; // < <= > >= give a bool signal
final canShip = agreed & paid; // & | ^ on bools
final greeting = first + ', welcome'; // + on stringsCopy code to clipboard
num
Operators: + - * / ~/ % and < <= > >=
String
Operators: +
bool
Operators: & | ^
Read .value to redraw
A derived signal redraws a widget through its sources, so read .value in build. == and ! are not overloaded: compare .value instead.
Every generated model has model.signal(context). Pass it to the generated page to redraw on each change.
Widget liveArticle(BuildContext context, Article article) {
final DVSignal<Article> current = article.signal(context);
return Article.Page.signal(current);
}Copy code to clipboard
// Register one instance at startup.
DV.global<Cart>(Cart());
// Read it anywhere. context.global redraws the widget when it is replaced.
final Cart cart = DV.global<Cart>();
final Cart same = context.global<Cart>();
// A namespace keeps two registrations of one type apart.
DV.global<Cart>(Cart(), 'wishlist');
final Cart wishlist = DV.global<Cart>(null, 'wishlist');Copy code to clipboard
DV.global<T>(instance) registers. DV.global<T>() reads, and throws when nothing is registered.
context.global<T>() reads and redraws the widget when the object is replaced.
Use it for app-wide objects. There is no separate service container.
DV.lifecycle.app.listen((DVAppLifecycle state) {
if (state == DVAppLifecycle.backgrounded) {
// Save a draft before the app is paused.
}
});Copy code to clipboard
DV.lifecycle.app and DV.lifecycle.build are read-only.
context.lifecycle.page, .request and .transaction exist inside a page, a request or a transaction.
Use .listen or .changes. Reading .value in build does not redraw.
Partial
Spec section: Lifecycle Signals
Planned work and implementation limits
DV.lifecycle.build never changes at run time.
A page moves through created, ready, active, disposing and disposed. Its loading and leaving states are not emitted.
The app never reports suspended or resuming, and a request never reaches completed.
Built
Spec section: State
FSL-1.1-MIT licensed. Built with Dartvel.
Dartvel is made by
To the bottom