a2ui-project / a2ui-project/a2ui
[spec] children are unkeyed, making it impossible to move children correctly
- 主要语言
- TypeScript
- 星标
- 16.4k
- 派生
- 1.3k
- 平均合并
- 2 天 13 小时
- 30 天内合并 PR
- 134
描述
## Problem
Consider this example from https://a2ui.org/specification/v0.9.1-a2ui/#collection-scopes-relative-paths:
Data model:
```
{
"company": "Acme Corp",
"employees": [
{"name": "Alice", "role": "Engineer"},
{"name": "Bob", "role": "Designer"}
]
}
```
Component definition:
```
{
"id": "employee_list",
"component": "List",
"children": {
"path": "/employees",
"componentId": "employee_card_template"
}
},
{
"id": "employee_card_template",
"component": "Column",
"children": ["name_text", "company_text"]
},
{
"id": "name_text",
"component": "Text",
"text": { "path": "name" }
},
{
"id": "company_text",
"component": "Text",
"text": { "path": "/company" }
}
```
A list of employees is renderer using the "employee_card_template" template component. On the first render everything is correct. However, consider a data update that swaps Alice and Bob:
```
{
"company": "Acme Corp",
"employees": [
{"name": "Bob", "role": "Designer"}
{"name": "Alice", "role": "Engineer"},
]
}
```
Because `List` children are unkeyed by anything, the data for "Bob" will flow into the card that used to render "Alice" and vice versa. This may produce correct visual result in basic (e.g. read-only) cases. However, this breaks in the following situations:
* If a screen reader focus is focused on Bob, instead of the focus moving with the widget to its new location, the data underneath the screen reader focus will unexpectedly be replaced with Alice. There will also be no screen reader notification to the user about the order change.
* If the user made a selection (e.g. on the web), that selection will be lost.
* If employee cards are editable the editing state may get corrupted, or simply confuse the user.
* If employee card widgets are stateful, their state will not move to a new location in the list, but instead will receive data for a wrong employee, which could violate some business rules.
## Proposal
The data optionally supplies an identifier:
```
{
"company": "Acme Corp",
"employees": [
{"id": "123", "name": "Bob", "role": "Designer"}
{"id": "234", "name": "Alice", "role": "Engineer"},
]
}
```
The list provides the property name that should be used as the child key, and the runtime applies it to every child widget:
```
{
"id": "employee_list",
"component": "List",
"children": {
"path": "/employees",
"componentId": "employee_card_template",
"key": "id" // NEW!
}
}
```
Now that widgets are keyes, the respective UI framework can move the widgets around preserving their state.
贡献指南
调研方向
Look at the List component implementation and how it handles children. The spec change involves adding a 'key' property to the children mapping. Examine the runtime's widget creation and update logic to understand where keys need to be applied. Check existing tests for list rendering to see how to add tests for keyed children.
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- typescript
- 领域
- frontend
- Issue 类型
- 功能
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 活跃
- 描述清晰度
- 描述清楚
- 新手友好度
- 45/100