-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tracked properties accessed in Array.prototype.map
and then updated don't retrigger render
#18858
Comments
Also, I went back and added tracked versions of the objects and arrays using https://github.com/pzuraq/tracked-built-ins @tracked
course = {
attributes: new TrackedObject({
calendar: new TrackedObject({
dates: new TrackedArray([
new TrackedObject({id: "monday", attributes: new TrackedObject({ lessonId: "a"}) }),
new TrackedObject({id: "tuesday", attributes: new TrackedObject({ lessonId: "a"}) }),
new TrackedObject({id: "wednesday", attributes: new TrackedObject({ lessonId: "a"}) }),
new TrackedObject({id: "thursday", attributes: new TrackedObject({ lessonId: "a"}) }),
new TrackedObject({id: "friday", attributes: new TrackedObject({ lessonId: "a"}) }),
])
})
})
} However, I got the same result :-( The value I calculated by mapping over the nested array did not update. |
This is expected behavior, though I can see why it's confusing. The issue is that if you want to update a piece of non-tracked state using get countOfUniqueLessonIds(){
return this.course.attributes.calendar.dates.map(date => {
return get(date.attributes, 'lessonId');
}).uniq().length
} Ember cannot know ahead of time that you plan to update You should really only do this if your state is highly dynamic though, or if you're using classic patterns and trying to update the code. The modern solution would be to create a class that annotates the tracked properties: class Attributes {
@tracked lessonId;
constructor(lessonId) {
this.lessonId;
}
}
export default class ApplicationController extends Controller {
@tracked
course = {
attributes: {
calendar: {
dates: [
{id: "monday", attributes: new Attributes("a") },
{id: "tuesday", attributes: new Attributes("a") },
{id: "wednesday", attributes: new Attributes("a") },
{id: "thursday", attributes: new Attributes("a") },
{id: "friday", attributes: new Attributes("a") }
]
}
}
}
} If you're dealing with dynamic classes where you don't know the tracked keys ahead of time, or you find that making classes for every case is burdensome, and you don't need to support IE11, you could consider using tracked-built-ins: import { tracked } from 'tracked-built-ins';
export default class ApplicationController extends Controller {
@tracked
course = {
attributes: {
calendar: {
dates: [
{id: "monday", attributes: tracked({ lessonId: "a"}) },
{id: "tuesday", attributes: tracked({ lessonId: "a"}) },
{id: "wednesday", attributes: tracked({ lessonId: "a"}) },
{id: "thursday", attributes: tracked({ lessonId: "a"}) },
{id: "friday", attributes: tracked({ lessonId: "a"}) }
]
}
}
}
} |
hmm, if |
@pzuraq Thank you so, so, so much for the clear explanation! I can confirm accessing it with Ember.get works! That's awesome -- I'm really excited to hear this. We've used Ember.get for years, so continuing to do that isn't a big deal at all. Tracked is a pretty magical (in a good way) so needing to using Ember.get in these situations is totally fine. Are there any perf reasons to do instead creating classes? That's an option we could look at (though would be more work) if we're going to be better off perf wise. After reading your message, I went back to double check it wasn't working with new TrackedObject (or tracked) and I can confirm that still doesn't work. I've updated the twiddle. |
ahhhh 🤦♂ this is yet another issue caused by the mandatory setter. We really need to prioritize removing this. Apparently the way it does I'll need to patch this upstream in Perf-wise, there are some benefits to using class definitions. For instance, they ensure that the shape of your classes is always the same, which can have massive benefits in hot paths. I've heard that browsers are looking to optimize them further, but it's hard to say how much benefit that'll be. The tradeoff is bytesize - more classes does mean more to download. If you are going to be enumerating a reasonably sized set of classes that are contained, and well defined, I recommend always using classes. This helps you in three ways:
If you're going to working with a lot of dynamic class definitions though, maybe ones that have various combinations that can be highly dynamic, I would not try to do this. It will be a huge pain to enumerate all of them, maintain them, and it will cost a large amount in terms of byte-size. You can try to strike a balance between the two, as well. Usually, part of your data structure is well defined, and part of it is less-so. You can use a class for the well defined bits, and use Hope this helps! |
@pzuraq That's SUPER helpful! Thank you so, so much! I can't thank you enough! |
I'm going to close this issue and work to fix it upstream in |
Hi!
I'm sorry in advance for the title -- it's a bit hard to describe. Here's what's going on:
Let's say you have this component/controller:
And then you have a getter which calculates something. E.g.:
and render it to your template:
And then you update a value deep in the object:
The getter won't update, even though the value will be updated:
Here's a twiddle:
https://ember-twiddle.com/4598ec7b9b56b1d6db3acc841f3728f7?openFiles=controllers.application%5C.js%2C
To reproduce:
I've been running into this for a few weeks with 3.17.x and took a minute to try to create a reproduction. Is this expected behavior? If so, how should we handle these situations in ember apps?
As a point of context, in pre-Octane apps, I'd add a computed property and it would work. To get around this, I'm just adding computed properties to my glimmer components. As it's a rather deep object, I hack it by having the CP look at property I update each change (
@computed('internalVersion')
) or I'll do a few computed properties due to limitations around@each
.Let me know if there's anything I can do to help if this isn't expected behavior!
The text was updated successfully, but these errors were encountered: