a2ui-project / a2ui-project/a2ui

In v0.9 remove subscribeToValue from data model

Aperta
#1,857 1 commento 0 reazioni 1 assegnatario Rivendicata da @jacobsimionato Vedi su GitHub
component: genui P3 status: first-line-handled type: feature/enhancement
Lingua principale
TypeScript
Stelle
16.4k
Fork
1.3k
Merge medio
2g 13h
PR unite (30g)
134

Descrizione

_↴ Ported from [flutter/genui#701](https://github.com/flutter/genui/issues/701) — originally opened by [jacobsimionato](https://github.com/jacobsimionato) on 2026-02-08._
_Original labels: front-line-handled_
_Original assignees: [gspencergoog](https://github.com/gspencergoog)_

---

For context - see https://github.com/flutter/genui/blob/feature/v0.9-migration/packages/genui/lib/src/model/data_model.dart

# Flutter Data Model Changes: Removing `subscribeToValue`

## Overview

This document proposes a simplification of the `DataModel` API in the Flutter renderer (`genui`) by removing the `subscribeToValue` method and consolidating subscription logic into a single `subscribe` method.

**Current State:**
The Flutter implementation currently offers two subscription methods:
1. `subscribe(path)`: Notifies on changes to the path, its ancestors, and its descendants.
2. `subscribeToValue(path)`: Notifies on changes to the path and its ancestors, but *ignores* descendants unless the specific value reference at `path` changes.

**Problem:**
The distinction between these two methods is subtle and rooted in object identity semantics that are often mismatched with the nature of JSON data models. In a JSON tree:
- If a leaf node (child) changes, the parent container has conceptually changed as well.
- Subscribing to a container (Map/List) usually implies an interest in its contents.
- The `subscribeToValue` optimization relies on object identity, which can be misleading if the underlying data structure is mutable or if the update mechanism replaces parent objects (which `DataModel` often does).

**Proposal:**
Remove `subscribeToValue` and standardize on the behavior of `subscribe` (notifying on ancestor, self, and descendant changes). This aligns the Flutter implementation with the proposed Web v0.9 implementation and the conceptual model of a JSON tree.

## API Changes

### 1. Remove `subscribeToValue`

The `subscribeToValue` method will be deprecated and removed.

**Before:**
```dart
// Notifies only if value at path changes identity
final valueNotifier = dataModel.subscribeToValue(DataPath('/user/name'));
```

**After:**
```dart
// Notifies if value at path, or any parent/child path changes.
// Returns a ValueNotifier which acts as the Subscription object.
// Listeners are added to this returned notifier.
final valueNotifier = dataModel.subscribe(DataPath('/user/name'));
```

### 2. Update `subscribe` Behavior (if needed)

Ensure `subscribe` correctly handles the "container semantics":
- **Ancestor Update:** If `/user` is replaced, listeners at `/user/name` are notified.
- **Descendant Update:** If `/user/name` is updated, listeners at `/user` are notified.
- **Self Update:** If `/user/name` is updated, listeners at `/user/name` are notified.

The current Flutter implementation of `subscribe` already supports this "bubbling up" notification for descendants.

## Rationale

1. **Conceptual Consistency:** A JSON object is a container. Changing a property inside it changes the object's state. Listeners to the object should be notified.
2. **API Simplicity:** Having two subscribe methods with subtle differences confuses consumers and increases the API surface area.
3. **Platform Parity:** Aligning with the Web v0.9 design ensures that A2UI renderers behave consistently across platforms, simplifying cross-platform development and testing. The Web `subscribe` method returns a `Subscription` object with an `onChange` callback property, which is conceptually similar to Flutter's `ValueNotifier` (an object you add listeners to).
4. **Reduced Complexity:** Removes the need for separate subscription maps (`_subscriptions` vs `_valueSubscriptions`) and the complex conditional logic in `_notifySubscribers` to handle them differently.

## Migration Guide

Existing usages of `subscribeToValue` should be replaced with `subscribe`.

**Example Migration:**

```dart
// OLD
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Only wanted updates if this specific string changed
return ValueListenableBuilder(
valueListenable: dataModel.subscribeToValue(path),
builder: (context, value, child) => Text(value ?? ''),
);
}
}

// NEW
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Now receives updates if children change too (though strings don't have children)
// For containers, this means more updates, but correct ones.
return ValueListenableBuilder(
valueListenable: dataModel.subscribe(path),
builder: (context, value, child) => Text(value ?? ''),
);
}
}
```

## Impact on Performance

Replacing `subscribeToValue` with `subscribe` might trigger more frequent notifications for listeners attached to container nodes (Maps/Lists). However, in typical UI patterns:
- Leaf nodes (Strings, Numbers) have no descendants, so behavior is identical.
- Container nodes are usually bound to Lists or Layouts that *need* to update when their children change.
- The `ValueNotifier` in Flutter checks for equality (`==`) before notifying listeners. If the data update results in the same value (e.g. same String), no notification occurs, preserving the optimization where it matters most.

---

### 2 comment(s) from the original issue

**[jacobsimionato](https://github.com/jacobsimionato)** commented on 2026-02-08:

WDYT @gspencergoog , does this make sense?

---

**[gspencergoog](https://github.com/gspencergoog)** commented on 2026-02-09:

Yes, this makes sense. Fewer ways to do the same thing is better: it removes the decision around what to choose, and I think that the current distinction isn't really all that useful anyhow.

And, it's actually not even used at the moment.

Guida per i contributori

Apri la guida per i contributori

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.