[英]How to update nested state in Ember Octane
So my situation is as follows: I got a component with a couple of input fields that represent a contact and are filled with data from a service:所以我的情况如下:我得到了一个包含几个输入字段的组件,这些输入字段代表一个联系人并填充了来自服务的数据:
@service('contact-data') contact;
Each field stands for one property that is accessed via每个字段代表一个通过访问的属性
{{contact.properties.foo}}
I have the properties saved as a JS object to easily filter out empty fields when using them and I tracked it with @tracked
like so:我将属性保存为 JS 对象,以便在使用它们时轻松过滤掉空字段,并使用
@tracked
跟踪它, @tracked
所示:
export default class MyService extends Service {
@tracked properties = {id: 0, foo: "", bar : "abc", };
@action updateProperty(name, value) {
this.properties[name] = value;
}
}
However, the properties do not re-render properly in the component and the textfields do not get updated.但是,属性不会在组件中正确重新呈现,并且文本字段不会更新。
I'd appreciate any help with this!我将不胜感激! Thanks!
谢谢!
Any time you have a bunch of nested state like that which needs to be tracked, just tracking the top-level object won't cause updates to the internals of that object to propagate out.任何时候你有一堆需要跟踪的嵌套状态,只跟踪顶级对象不会导致对该对象内部的更新传播出去。 You need to track the internal properties, or you need to reset the whole object you're tracking.
您需要跟踪内部属性,或者您需要重置您正在跟踪的整个对象。
You have basically two rough options for dealing with updates to those internal properties:您基本上有两个粗略的选项来处理这些内部属性的更新:
@tracked
on the fields, and instantiate the utility class when you create the service.@tracked
的实用程序类中,并在创建服务时实例化该实用程序类。 Then updates to those fields will update.this.properties = { ...this.properties, foo: newValue };
this.properties = { ...this.properties, foo: newValue };
Of these, (1) is pretty much always going to be the cheapest and have the best performance.其中,(1) 几乎总是最便宜且性能最好的。 Doing (2.1) will be a little more expensive, because it requires the use of a
Proxy
, but not enough that you would normally notice.做 (2.1) 会有点贵,因为它需要使用
Proxy
,但还不够,你通常会注意到。 Doing (2.2) will end up triggering a re-render for every property in the properties
used anywhere in the app, even if it didn't change.这样做(2.2)将最终触发重新绘制在每个属性
properties
在该应用的任何使用,即使它并没有改变。
In the case you've described, it appears the fields are well known, which means you should reach for that class.在您所描述的情况下,这些字段似乎是众所周知的,这意味着您应该访问该类。 The solution might look something like this:
解决方案可能如下所示:
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 updateFoo(newValue) {
this.properties.foo = newValue;
}
@action updateBar(newValue) {
this.properties.bar = newValue;
}
}
Note that @tracked
installs getters and setters in place of plain class properties , so if you need to use this for a JSON payload somewhere or similar, you'll also want to implement toJSON
on the utility class:请注意,
@tracked
安装 getter 和 setter 代替普通类属性,因此如果您需要将其用于某处或类似地方的 JSON 有效负载,您还需要在实用程序类上实现toJSON
:
class TheProperties {
@tracked id;
@tracked foo;
@tracked bar;
toJSON() {
let { id, foo, bar } = this;
return { id, foo, bar };
}
}
There's another add-on that does basically the same thing for Array and Objects as tracked-built-ins.还有另一个附加组件对数组和对象的作用与跟踪内置函数基本相同。
It's a proxy that basically notifies the root that an update has occurred somewhere.它是一个代理,基本上通知根某处发生了更新。 The advantage against tracked-built-ins is that the nesting depth is not limited as it's common for JSON to have deep nesting.
与跟踪内置函数相比的优势在于,嵌套深度不受限制,因为 JSON 具有深度嵌套是很常见的。
The drawbacks are similar to tracked-built-ins in terms of performance.在性能方面,缺点类似于内置跟踪。 Use it sparingly and try not to use it in tables with hundreds/thousands of rows as re-rendering is going to be not performant.
谨慎使用它并尽量不要在具有数百/数千行的表中使用它,因为重新渲染将没有性能。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.