如何在 Ember Octane 中更新嵌套状态
How to update nested state in Ember Octane
所以我的情况是这样的:
我得到了一个组件,其中包含几个代表联系人的输入字段,并填充了来自服务的数据:
@service('contact-data') contact;
每个字段代表通过
访问的一个属性
{{contact.properties.foo}}
我将属性保存为 JS 对象,以便在使用它们时轻松过滤掉空字段,并且我使用 @tracked
跟踪它,如下所示:
export default class MyService extends Service {
@tracked properties = {id: 0, foo: "", bar : "abc", };
@action updateProperty(name, value) {
this.properties[name] = value;
}
}
但是,组件中的属性未正确重新呈现,文本字段未更新。
如有任何帮助,我将不胜感激!谢谢!
任何时候你有一堆 nested 需要跟踪的状态,只跟踪 top-level 对象不会导致内部更新该对象传播出去。您需要跟踪内部属性,或您需要重置您正在跟踪的整个对象。
您基本上有两个粗略的选项来处理这些内部属性的更新:
- 如果对象具有 well-known 形状,将其提取到在字段上使用
@tracked
的实用程序 class 中,并在创建时实例化实用程序 class服务。然后对这些字段的更新将更新。
- 如果对象真的像哈希映射一样被使用,那么您有两个变体选项:
- 如果不需要 IE11 支持,请使用 https://github.com/pzuraq/tracked-built-ins
- 做一个“纯功能更新”,你可以做类似
this.properties = { ...this.properties, foo: newValue };
其中,(1) 几乎总是最便宜且性能最好的。执行 (2.1) 会稍微贵一点,因为它需要使用 Proxy
,但还不够您通常会注意到的。执行 (2.2) 最终会触发 re-render for every 属性 in the properties
used anywhere in the app,即使它没有改变。
在您所描述的情况下,这些字段似乎是众所周知的,这意味着您应该找到那个 class。解决方案可能如下所示:
import Service from '@ember/service';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
class TheProperties {
@tracked id;
@tracked foo;
@tracked bar;
}
export default class MyService extends Service {
properties = new TheProperties();
@action updateProperty(name, value) {
this.properties[name] = value;
}
}
请注意 @tracked
installs getters and setters in place of plain class properties,因此如果您需要将其用于某处或类似的 JSON 有效载荷,您还需要在 toJSON
上实施实用程序 class:
class TheProperties {
@tracked id;
@tracked foo;
@tracked bar;
toJSON() {
let { id, foo, bar } = this;
return { id, foo, bar };
}
}
还有一个 add-on 对 Array 和 Objects 做的事情与 tracked-built-ins 基本相同。
它是一个代理,基本上通知根某处发生了更新。相对于 tracked-built-ins 的优点是嵌套深度不受限制,因为 JSON 有很深的嵌套是很常见的。
缺点在性能方面与tracked-built-ins类似。谨慎使用它,尽量不要在行数为 hundreds/thousands 的表中使用它,因为重新呈现的性能不佳。
所以我的情况是这样的: 我得到了一个组件,其中包含几个代表联系人的输入字段,并填充了来自服务的数据:
@service('contact-data') contact;
每个字段代表通过
访问的一个属性{{contact.properties.foo}}
我将属性保存为 JS 对象,以便在使用它们时轻松过滤掉空字段,并且我使用 @tracked
跟踪它,如下所示:
export default class MyService extends Service {
@tracked properties = {id: 0, foo: "", bar : "abc", };
@action updateProperty(name, value) {
this.properties[name] = value;
}
}
但是,组件中的属性未正确重新呈现,文本字段未更新。
如有任何帮助,我将不胜感激!谢谢!
任何时候你有一堆 nested 需要跟踪的状态,只跟踪 top-level 对象不会导致内部更新该对象传播出去。您需要跟踪内部属性,或您需要重置您正在跟踪的整个对象。
您基本上有两个粗略的选项来处理这些内部属性的更新:
- 如果对象具有 well-known 形状,将其提取到在字段上使用
@tracked
的实用程序 class 中,并在创建时实例化实用程序 class服务。然后对这些字段的更新将更新。 - 如果对象真的像哈希映射一样被使用,那么您有两个变体选项:
- 如果不需要 IE11 支持,请使用 https://github.com/pzuraq/tracked-built-ins
- 做一个“纯功能更新”,你可以做类似
this.properties = { ...this.properties, foo: newValue };
其中,(1) 几乎总是最便宜且性能最好的。执行 (2.1) 会稍微贵一点,因为它需要使用 Proxy
,但还不够您通常会注意到的。执行 (2.2) 最终会触发 re-render for every 属性 in the properties
used anywhere in the app,即使它没有改变。
在您所描述的情况下,这些字段似乎是众所周知的,这意味着您应该找到那个 class。解决方案可能如下所示:
import Service from '@ember/service';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
class TheProperties {
@tracked id;
@tracked foo;
@tracked bar;
}
export default class MyService extends Service {
properties = new TheProperties();
@action updateProperty(name, value) {
this.properties[name] = value;
}
}
请注意 @tracked
installs getters and setters in place of plain class properties,因此如果您需要将其用于某处或类似的 JSON 有效载荷,您还需要在 toJSON
上实施实用程序 class:
class TheProperties {
@tracked id;
@tracked foo;
@tracked bar;
toJSON() {
let { id, foo, bar } = this;
return { id, foo, bar };
}
}
还有一个 add-on 对 Array 和 Objects 做的事情与 tracked-built-ins 基本相同。
它是一个代理,基本上通知根某处发生了更新。相对于 tracked-built-ins 的优点是嵌套深度不受限制,因为 JSON 有很深的嵌套是很常见的。
缺点在性能方面与tracked-built-ins类似。谨慎使用它,尽量不要在行数为 hundreds/thousands 的表中使用它,因为重新呈现的性能不佳。