# 跟踪嵌套数据结构的另一种方法

**URL:** <https://meta.discourse.org/t/another-way-to-track-nested-data-structures/357978>\
**Category:** Development\
**Tags:** plugin-api, rest-api\
**Created:** [2025年三月19日 15:24 UTC](https://meta.discourse.org/t/another-way-to-track-nested-data-structures/357978 "2025-03-19T15:24:00Z")\
**Posts on this page:** 1\
**Showing post:** 1

<div class="post-metadata">

**Author:** ![bitmage](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/bitmage/32/389881_2.png) [@bitmage](https://meta.discourse.org/u/bitmage)\
**Post date:** [2025年三月19日 15:24 UTC](https://meta.discourse.org/t/another-way-to-track-nested-data-structures/357978/1 "2025-03-19T15:24:00Z")

</div>

`@tracked` 状态下的数组或对象在 Glimmer 组件中，当您更改数组/对象中的某个成员时，不会触发更新。

[此主题讨论了一些选项](https://meta.discourse.org/t/problem-tracking-nested-structure/320886) 以使您的视图正确更新。我想添加另一种方法，因为那里讨论的选项对我不起作用。

我的解决方法是：与其一次分配一个元素，不如一次性分配整个数组。这种相同的策略也适用于对象或任何其他数据结构。

在 Glimmer 组件中：

```javascript
@tracked categories = [];

constructor() {
  super(...arguments);
  this.loadAllData();
}

async loadAllData() {
  const categories = []
  const waiting = this.siteSettings.county_fence_print_categories.split('|').map(async (cid, index) => {
    const data = await this.loadData(`/c/${cid}/l/latest.json?period=monthly`)
    return data.topic_list.topics
  })

  // 这是需要注意的行
  // 因为我们直接对数组进行赋值，它将触发更新。
  // 而推送到数组或按索引设置元素则不会触发更新。
  this.categories = await Promise.all(waiting)
}

async loadData(url) {
  try {
    const data = await ajax(url);
    //console.log(`Got data for ${url}:`, data)
    return data
  } catch (error) {
    console.error(`Failed to get data for ${url}:`, error);
  }
}

```

您也可以通过部分更新来完成此操作。重要的是让 JavaScript 检测到正在分配_不同的值_。因此，虽然 `.concat` 会起作用，因为它会生成一个与旧数组不同的新数组：

```javascript
this.categories = this.categories.concat(newValue)

```

使用 `.push` 可能_不会_起作用，因为结果数组与原始数组具有相同的对象 ID，因此 JavaScript 认为没有任何变化。

```javascript
this.categories.push(newValue)
this.categories = this.categories

```

如果您正在处理一个对象，生成新对象的简单方法是使用 `Object.assign()` - 它会创建一个新的、扩展的数据结构，就像上面的 `.concat` 一样。

对于 Vue.js 等其他框架来说，这早已是常态——您可以找到关于此的讨论，可以追溯到 10 年前。这与 JavaScript 中的实现方式有关，可能是父对象上的 getter/setter 或 `observe` API。但如果它是通过 observe API 实现的，那么对于这种行为的借口就少一些了，因为[可以轻松切换 subtree 标志](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe#subtree)…也许他们出于性能考虑而选择不这样做，当观察深度嵌套的结构时？但跑题了，这些是底层库的实现细节。上面的解决方法应该可以帮助您解决这个问题。

---

_[View the full topic](https://meta.discourse.org/t/another-way-to-track-nested-data-structures/357978)._
