Let’s say we have the following scenario:
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
export default class extends Component {
@tracked array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
get evens() {
console.log("evens called");
return this.array.filter((n) => n % 2 === 0);
}
@action
updateEvens() {
this.array = [...this.array, 12, 14, 16, 18, 20];
}
}
<div>Length: {{evens.length}}</div>
{{#each evens as |i|}}
<div>{{i}}</div>
{{/each}}
<button type="button" {{on "click" this.updateEvens}}>
Click Me
</button>
With the above, I see “evens called” logged to the console twice; twice on initial render and twice when I click the button. This is happening from {{evens.length}}
and {{#each evens as |i|}}
.
In order for evens
to be called only once on each render, I can do either of the following:
@computed("array.length")
get evens() {
console.log("evens called");
return this.array.filter((n) => n % 2 === 0);
}
or I can use the @cached
decorator via ember-cached-decorator-polyfill:
@cached
get evens() {
console.log("evens called");
return this.array.filter((n) => n % 2 === 0);
}
Assuming evens
was computationally expensive, would you recommend one of these approaches or something else?