a2ui-project / a2ui-project/a2ui

[spec] children are unkeyed, making it impossible to move children correctly

未关闭
#1,745 5 条评论 0 个 reaction 已指派 1 人 已指派给 @gspencergoog 在 GitHub 查看
component: specification P1 type: feature/enhancement
主要语言
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

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。