Dartvel, home
Docs
Features
Studio
Cloud
Compared

Search the site

GitHub
pub.dev

GETTING STARTED

Getting started
Existing Flutter apps
Existing Native apps
Run on your phone

APP

UI and styling
Routing
State
Accessibility
Keyboard shortcuts
Localization
Devices and desktop
Native device access
Media, 3D and XR

DATA

Data models
Forms
Search
Sync and offline
Import and export
Change capture
Database
Cache
File storage
Images
Privacy and erasure

BACKEND

Backend functions
Auth and sessions
Authorization
Queues and jobs
Workers and memory
Notifications and mail
Outbound HTTP
AI
Webhooks
GraphQL and OpenAPI
API keys and OAuth
Multi-tenancy
Billing and commerce
Modules

OPERATIONS

Edge security
Secrets and environments
Monitoring
Releases

SHIPPING

Build targets
Telegram Mini Apps
Static web hosting
Servers and deploying

REFERENCE

Testing
CLI reference
Coding agents

APP

State

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

Create a signal with context.signal

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.

Set, update and read a signal

quantity.value = 3; // set
quantity.update((int n) => n + 1); // set from the current value
final int now = quantity.read(); // read without subscribing

Copy code to clipboard

Derive signals with operators

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 strings

Copy 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.

Make a model reactive

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

Share one object with DV.global

// 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.

Observe the app lifecycle

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.

Status

Built

Spec section: State

PREVIOUS Routing File pages, parameters, layouts and links
NEXT Accessibility Build-time audit, switch control and remote keys
GitHub
pub.dev
npm
Acknowledgements
Privacy
Terms

FSL-1.1-MIT licensed. Built with Dartvel.

Dartvel is made by

SigmaDev Digital

To the bottom