a2ui-project / a2ui-project/a2ui
In v0.9 remove subscribeToValue from data model
- 主要言語
- TypeScript
- スター
- 16.4k
- フォーク
- 1.3k
- 平均マージ
- 2日 13時間
- マージ済み PR(30日)
- 134
説明
_↴ 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.
コントリビューションガイド
調査の方向性
The change targets the DataModel API in the Flutter renderer, specifically the file packages/genui/lib/src/model/data_model.dart. Start by understanding the current subscribe and subscribeToValue methods and their notification logic. Remove subscribeToValue, update any internal subscription maps, and ensure subscribe handles ancestor, self, and descendant changes correctly. Test by verifying that existing widgets using subscribeToValue now work with subscribe and that notifications bubble appropriately.
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- dart, flutter
- 領域
- backend-api-design
- issue の種類
- リファクタリング
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 活発さ
- 静か
- 明瞭さ
- 明確に書かれている
- 初心者へのやさしさ
- 45/100