ArkTS UI 备忘

一个状态更新未引起UI重绘的问题

案例是一个ToDo List的应用, 先定义一个模型, 状态变更主要是它:

@Observed
class TodoItem {
  id: string = ''
  text: string = ''
  completed: boolean = false
  editMode: boolean = false
  finishTime: string = ''
}

再定义基本UI:

@Component
struct TodoListItem {
  @ObjectLink item: TodoItem

  build() {
      Row() {
        // 复选框
        Toggle({type: ToggleType.Checkbox, isOn: this.item.completed})
        // Checkbox().select(this.item.completed) // select方法可能会触发事件, 改用Toggle
          .onChange((isOn: boolean) => {
            console.log(`${this.item.text}, ${isOn}`)
            this.item.completed = isOn
            this.item.finishTime = isOn ? new Date().toLocaleString() : ''
          })
    ... // 略

页面:

@Entry
@Component
struct TodoList {
  @State todos: TodoItem[] = [
    { id: '1', text: '学习ArkUI', completed: false, editMode: false, finishTime: '' },
    { id: '2', text: '开发TODO应用', completed: true, editMode: false, finishTime: '2025-10-21 13:17:22' },
    { id: '3', text: '测试滑动删除', completed: false, editMode: false, finishTime: '' }
  ]

  build() {
    Column() {
      ForEach(this.items, (item: TodoItem) => {
        TodoListItem({item})
      })
    }
  }
}

在Entry里通过Foreach送入, 代码略, 运行后, 发现点击复选框, 状态变更了, 但是UI没有更新. 跟AI PK了一天, 发现是数据源用了字面量来初始化TodoListItem对象(测试即使加as ToDoItem也不行), 导致状态变更后, UI没有重绘. 修改为new TodoListItem()后, 问题解决.

  constructor(id: string, text: string, completed?: boolean, editMode?: boolean, finishTime?: string) {
    this.id = id;
    this.text = text;
    this.completed = completed || false;
    this.editMode = editMode || false;
    this.finishTime = finishTime || '';
  }

这个一定要记录一下, 巨坑, 用字面量本为了省个构造函数, 结果不但需要重复写字面量, 还导致状态监控链条打破了.