diff --git a/guides/release/in-depth-topics/autotracking-in-depth.md b/guides/release/in-depth-topics/autotracking-in-depth.md index cfec653b84..3a92811b8c 100644 --- a/guides/release/in-depth-topics/autotracking-in-depth.md +++ b/guides/release/in-depth-topics/autotracking-in-depth.md @@ -321,4 +321,88 @@ class ShoppingList { } ``` +## Caching of tracked properties + +In contrast with computed properties from pre-Octane, autotracked properties +are not cached. This means that an autotracked property will always be +recomputed, regardless of whether its dependencies have changed. The following +example shows how this works: + +```js +import { tracked } from '@glimmer/tracking'; + +let count = 0; + +class Person { + @tracked firstName = 'Jen'; + @tracked lastName = 'Weber'; + + get fullName() { + ++count; + return `${this.firstName} ${this.lastName}`; + } +} + +let person = new Person(); + +console.log(person.fullName); // Jen Weber +console.log(count); // 1; +console.log(person.fullName); // Jen Weber +console.log(count); // 2; + +person.firstName = 'Jennifer'; + +console.log(person.fullName); // Jennifer Weber +console.log(count); // 3; +``` + +This works fine in most cases. But sometimes you want a bit more control over +the recomputation, for instance if the computation that happens in the getter +is very expensive. In that case, you want to cache the value in between calls +when the dependencies haven't changed. You want to recompute only if one of the +dependencies has been modified. + +The way to achieve this is through Ember's [cache +API](https://github.com/emberjs/rfcs/blob/master/text/0615-autotracking-memoization.md). +It's not yet available in Ember.js core but you can use the API today with the +[ember-cache-primitive-polyfill](https://github.com/ember-polyfills/ember-cache-primitive-polyfill) +addon. + +Using `createCache`, we can cache an autotracked property. The property can +then be consumed with the `getValue` function. The way it works is as follows: + +```js +import { tracked } from '@glimmer/tracking'; +import { createCache, getValue } from '@glimmer/tracking/primitives/cache'; + +let count = 0; + +class Person { + @tracked firstName = 'Jen'; + @tracked lastName = 'Weber'; + + // `#` indicates a private field on the class. + #fullNameCache = createCache(() => { + ++count; + return `${this.firstName} ${this.lastName}`; + }) + + get fullName() { + return getValue(this.#fullNameCache); + } +} + +let person = new Person(); + +console.log(person.fullName); // Jen Weber +console.log(count); // 1; +console.log(person.fullName); // Jen Weber +console.log(count); // 1; + +person.firstName = 'Jennifer'; + +console.log(person.fullName); // Jennifer Weber +console.log(count); // 2; +``` +