Recently I encountered an use case of @cached
from tracked-toolbox when writing a Glimmer component with autotracking. Here is an example code snippet:
import Component from '@glimmer/component';
/**
* Example usage
* <PersonInfo
* @a={{this.objA}}
* @b={{this.stringB}}
* @c={{this.intC}}
* />
* Where objA can be a large object
*/
export default class PersonInfo extends Component {
/**
* I hope @cached here can help avoid re-running output getter in each
* of the other getters, e.g. this.msg, this.link, this.name
* But whenever any input args changes it triggers update
* (i.e. parent run this.objA = newObj)
*/
get output() {
return someExpensiveLogic(this.args.a, this.args.b, this.args.c);
}
get msg() {
return translate(this.output.msg);
}
get link() {
return convert(this.output.link);
}
get name() {
return change(this.output.name);
}
}
{{!-- In the template --}}
<div>
{{this.name}}
{{this.msg}}
{{this.link}}
</div>
Without using @cached
, the above code will execute the output
getter 3 times when rendering, once for each of msg
, link
and name
.
I also thought about building my own cache for output
, but it requires me to manually keep track of which state is used and hash them, which could be expensive and hard to maintain.
From my understanding, what @cached
provides is an access to the "global tag" in the auto tracking system, so I can rely on that tag to determine when the cache needs refresh.
Since this is not supported in a company project I work on for now, I hope this usage it can encourage us to add such support later.
Note: I found that @cached
is convenient wrapper of
import { createCache, getValue } from '@glimmer/tracking/primitives/cache';
So fundamentally what I need is @glimmer/tracking/primitives/cache
.
Posting a follow up here based on an offline discussion.
This is a valid usage of the
@cached
utility from tracked-toolbox. The narrow use case meets the below requirements:output
getter is expensive.output
is used multiple times in other getters in JS. (Ifthis.output
is only used directly in the template, it will already have exactly the same semantics around rerunning as it does with@cache
.)output
getter, using@cache
will not evaluate changes of the arguments' values, which means ifthis.args.b
is set to the same value as before, theoutput
getter will still rerun. This is not a concern in this use case, because I know the parent will not set the same value in input args.