4. Connect reactive state to your UI
The session exposes read-only MobX-observable getters. Documents remain immutable snapshots; a document reference you saved earlier never changes in place.
From an action to a visible update
Canvas gestures and toolbar commands use the same engine transaction pipeline. The engine validates the operation, prepares state and resolved geometry, then publishes the update. The session batches observable invalidations for that publication. The canvas already subscribes internally; your own controls can observe the public session getters.
Rebuild the toolbar
Add flutter_mobx: ^2.4.0 to your app dependencies, run flutter pub get, and import package:flutter_mobx/flutter_mobx.dart. Replace buildToolbar() in the Column's children with:
dart
Observer(
builder: (context) => buildToolbar(),
),Inside buildToolbar, use the current history state:
dart
// Undo button:
onPressed: session.canUndo ? () => showDecision(session.undo()) : null,
// Redo button:
onPressed: session.canRedo ? () => showDecision(session.redo()) : null,Reads of selection, activeTool, canUndo, canRedo, isInteracting, document, scene, snapshot, configuration, and cameraState inside an Observer are tracked. Only changes to the values that it reads invalidate it. Read those values during the builder's execution, not exclusively in a button's later onPressed callback. Nested child widgets need their own Observer when those children perform the reads.
There is no manual subscription or revision counter to dispose. Observer manages its own reaction; your screen still owns and disposes the session after unmounting its canvas. Avoid wrapping the whole editor when a small toolbar or property control is sufficient. Kit consumes the engine session observables.
Choose the right subscription
| Your requirement | Subscribe with | Read |
|---|---|---|
| Toolbar availability, selection or active tool | Observer / MobX reaction | Tracked session getters |
| Save, audit or synchronize completed edits | addDocumentChangeListener | change.after, change.elements |
| Zoom label or camera overlay | addPresentationListener | session.cameraState |
Subscribe to one element
Read session.elementById(id) inside an Observer or MobX reaction when a control depends on one shape or connector. Unlike reading session.document, this does not invalidate the control when a different element changes. Removal returns null; Undo can restore the element and notify the same subscription.
For a pure-Dart listener, use session.watchElement(id). Its read-only value, addListener and removeListener follow the listen package's ValueListenable contract. Dispose the signal when its consumer is done.
The engine separates document, scene, selection, tool, history, interaction, camera and settings notifications. A selector is evaluated only when its domain changes and it has listeners. Element comparisons use only actively subscribed IDs on committed document changes; unchanged elements emit no notification. MobX attaches these subscriptions only while a reaction observes them and batches invalidations from one publication.
Built-in controls use these narrow subscriptions too. The inspector observes its displayed properties, diagnostics observe committed content, and overlays subscribe separately to geometry, camera, selection or alignment guides. Canvas rendering continues to receive live geometry during a drag.
The retained addListener API includes interaction previews and provisional text edits. MobX observers invalidate only when a tracked getter changes. Public document, scene and snapshot retain committed content while a gesture is previewing. A live notification therefore does not mean there is a new document to save. Completed change events exclude canceled gestures, selection and camera movement.
DrawingHooks.onChange observes the same completed events as document listeners. Use a hook for one configuration-owned callback, or independently removable listeners for separate consumers.
Bring your own state management
The existing callback boundary remains available to update a Riverpod provider, BLoC stream or MobX observable projection. Keep document edits as session commands; do not maintain a second mutable diagram in your state store. Subscribe when the consumer attaches and unsubscribe when it detaches. If a widget accepts a replaceable session, move subscriptions in didUpdateWidget as well.
Observers may read state and update host UI, but cannot synchronously issue another diagram edit during notification. Schedule any follow-up command after delivery and re-read current state then.
Checkpoint: Undo disables after exhausting history, and Redo updates after canvas edits as well as toolbar clicks. No manual refresh call is needed.