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
How do you tell a getter to only invalidate if the _value_ changes, rather than the tracked references accessed invalidate (for any reason) #20632
Comments
I do this with custom a decorator and a custom tag like this: but i have no idea if this is public api or whatever .. import { COMPUTE, TYPE, DIRYTABLE_TAG_ID, consumeTag, beginTrackFrame, endTrackFrame, beginUntrackFrame, endUntrackFrame, INITIAL } from '@glimmer/validator';
export default function cached(_target, _key, desc) {
const CACHE = new WeakMap();
return {
get() {
let tag = CACHE.get(this);
if (!tag) {
tag = new CachedTag(desc.get.bind(this));
CACHE.set(this, tag);
}
return tag.value;
}
};
}
class CachedTag {
revision = INITIAL;
cached_revision = INITIAL;
cached_value;
subtag;
getter;
constructor(getter) {
this.getter = getter;
}
[TYPE] = DIRYTABLE_TAG_ID;
[COMPUTE]() {
const subtag = this.subtag;
let revision = this.revision;
if (Array.isArray(subtag)) {
for (const tag of subtag) {
const value = tag[COMPUTE]();
revision = Math.max(value, revision);
}
} else {
const tag = subtag;
const value = tag[COMPUTE]();
revision = Math.max(value, revision);
}
if (this.cached_revision !== revision) {
this.cached_revision = revision;
beginUntrackFrame();
try {
if (this.cached_value !== this.value) {
this.revision = this.cached_revision;
}
} finally {
endUntrackFrame();
}
}
return this.revision;
}
get value() {
beginTrackFrame();
try {
this.cached_value = this.getter();
} finally {
this.subtag = endTrackFrame();
consumeTag(this);
}
return this.cached_value;
}
} Usage: import cached from '........./cached-decorator';
export default class TestComponent extends Component {
@tracked clock = new Date();
constructor(...args) {
super(...args);
setInterval(() => this.clock = new Date(), 125);
}
@cached get test() {
return this.clock.getSeconds();
}
} if you put in a template {{log this.test}} with my custom decorator / tag it will output into console:
without or with orginal cached:
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Something that comes close to this is
@dedupeTracked
fromtracked-toolbox
: https://github.com/tracked-tools/tracked-toolbox/tree/master#dedupetrackedbut it only works by intercepting the setting of a what-would-be-
@tracked
property.The situation I have is related to the URL, but the source of the data could be anything.
or generically,
for rendering performance reasons (like, maybe something downstream, depending on
localData
causes other things to happen, you want those other things to execute as few times as possible -- in this case, based on value-equality rather than reference-dirtiness.@cached
is a reference-based cache, and the references do change, so it doesn't work.What we need is something like
@dedupeTracked
, but for getters, and absorbing upstream changes.I don't think ember has a way to handle this.
Starbeam does, tho. So maybe the answer is to wait for better reactivity primitives.
https://www.starbeamjs.com/guides/advanced/equivalence.html
The text was updated successfully, but these errors were encountered: