Reactivity - #2219
Conversation
✅ Deploy Preview for ember-guides ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
9553b2f to
f93c0cf
Compare
- Motivation references the in-flight reactivity guides (ember-learn/guides-source#2219) instead of claiming docs are sparse - remove the derived-vs-cached clarification paragraph (the guides cover it; not an ambiguation) - move the RFC 615 relationship to the Appendix, without any de-emphasize/deprecate intent Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| previously in the same computation. | ||
| ``` | ||
|
|
||
| This is sometimes called the _backtracking assertion_: render evaluates your |
There was a problem hiding this comment.
-This is sometimes called the _backtracking assertion_: render evaluates your …
+This backtracking assertion evaluates your …| When a write that changes nothing shouldn't dirty anything, the decorator | ||
| accepts an options form, `@tracked({ equals })`, that skips invalidation |
There was a problem hiding this comment.
Very cool!
Depends on release of emberjs/ember.js#21471, right? starting with 7.3.0?
There was a problem hiding this comment.
yea, tho I think these docs are required to release in 7.3
@kategengler knows the task<->dependency chain.
|
@NullVoxPopuli this was a great read – thanks! Also very exited to learn about the overloaded tracked of 7.3. |
- Motivation references the in-flight reactivity guides (ember-learn/guides-source#2219) instead of claiming docs are sparse - remove the derived-vs-cached clarification paragraph (the guides cover it; not an ambiguation) - move the RFC 615 relationship to the Appendix, without any de-emphasize/deprecate intent Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Add RFC: Overload cached for non-class use Derived-state companion to RFC 1071 (overloaded tracked). Re-uses the Reactive/ReadOnlyReactive interfaces defined there; cached(fn, options) returns a read-only CachedValue. * Fill in proposal PR URL Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Do not conflate derived state with cached state Derived state is just plain functions and needs no API; cached() is opt-in memoization of a derivation. Reword Summary, Motivation, usage headings, and How We Teach accordingly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: guides link, drop terms paragraph, RFC 615 to appendix - Motivation references the in-flight reactivity guides (ember-learn/guides-source#2219) instead of claiming docs are sparse - remove the derived-vs-cached clarification paragraph (the guides cover it; not an ambiguation) - move the RFC 615 relationship to the Appendix, without any de-emphasize/deprecate intent Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Address review: drop equals, drop 'memoization' wording - remove the equals option from the proposed API entirely (calling fn is the expensive part; re-running it to discard the result is silly); noted as deferred in the Appendix - say caching, not memoization, throughout - reword the 'born a ReadOnlyReactive' sentence - drop the implementation-would-be-lower aside Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Apply suggestion from @NullVoxPopuli * Address review: get on ReadOnlyReactive, trim examples and mentions - no new CachedValue interface; add get to ReadOnlyReactive instead (an RFC 1071 oversight) and return ReadOnlyReactive from cached() - apply suggested guides sentence (drop 'over the years') - Starbeam only in prior art; resources are a different concept - remove the contrived nested-let template example Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: NullVoxPopuli-ai-agent <268630448+NullVoxPopuli-ai-agent@users.noreply.github.com> Co-authored-by: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds advanced reactivity guidance supporting RFC #1071’s release advancement.
Changes:
- Adds guides for root state, derived state, and effects.
- Expands autotracking documentation and cross-references.
- Updates navigation and spelling terminology.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
.local.dic |
Adds reactivity terminology. |
guides/release/pages.yml |
Adds reactivity navigation. |
guides/release/in-depth-topics/autotracking-in-depth.md |
Expands tracking references and examples. |
guides/release/in-depth-topics/reactivity/index.md |
Introduces the reactivity model. |
guides/release/in-depth-topics/reactivity/root-state.md |
Documents reactive root state. |
guides/release/in-depth-topics/reactivity/derived-state.md |
Documents derivations and caching. |
guides/release/in-depth-topics/reactivity/inputs-and-outputs.md |
Documents effects, lifetimes, and async behavior. |
Suppressed comments (1)
guides/release/in-depth-topics/reactivity/root-state.md:230
- Keeping a tracked array's identity stable is useful, but mutating it does not guarantee that only the changed entry's consumers invalidate: current
trackedArraywrites dirty the collection tag. Preserve the identity recommendation without promising narrower invalidation.
a one-item change gets treated as if the entire array were new. Retain
identity wherever possible: keep one long-lived tracked collection and mutate
it, so that the system invalidates only what actually changed. Replacement is
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| Storing derived values is sometimes pitched as an optimization. However, | ||
| autotracking already recomputes lazily, and only when inputs change, so the | ||
| optimization is usually imaginary. When a derivation really is expensive, you | ||
| can [cache it](../derived-state/#toc_caching) instead of promoting it to root | ||
| state. |
| `tracked` also works as a plain function. Called with a value instead of | ||
| applied as a decorator, it returns a standalone reactive value - root state | ||
| that isn't attached to any class: |
There was a problem hiding this comment.
while true, I'm not sure how beneficial it is to mention in these docs.
This is implementation caveats that are very edge casey.
| - Once-per-change semantics. If a derivation must observably run at most once | ||
| per change (because it allocates, logs, or is just very hot), `@cached` | ||
| guarantees that. |
There was a problem hiding this comment.
🤷 I don't know how to best phrase this. sounds good
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Suppressed comments (6)
guides/release/in-depth-topics/reactivity/root-state.md:209
- This copy guarantee does not hold for
trackedWeakMaportrackedWeakSet: weak collections are not iterable, so Ember wraps and mutates a supplied weak collection instead of cloning it. Narrow the guarantee or document that exception.
to know: the collection functions copy the data you pass in, so mutating the
tracked collection never mutates the original; and tracked collections are
shallow - `trackedObject`'s properties are tracked, but objects stored inside
it are ordinary objects unless you wrap them too. See
guides/release/in-depth-topics/reactivity/inputs-and-outputs.md:212
- A promise can reject with a falsy reason such as
undefinedornull. In that casestatusbecomesrejected, but this condition falls through to the success branch and dereferencesthis.user.value.namewhilevalueis still null. Select the branch fromstatus, which is the request-state discriminator.
{{else if this.user.error}}
guides/release/in-depth-topics/reactivity/index.md:114
- This overstates the scope and lifetime of the conditional dependency: another consumer can still be invalidated by
nickname, anddisplayNamestops depending on it if the condition later switches back. Describe invalidation through this getter and only while its branch is active.
While `useNickname` is `false`, changes to `nickname` don't invalidate
anything, because `displayName` never read it. If `useNickname` becomes
`true`, the next evaluation reads `nickname`, and from then on changes to it
propagate. The dependency graph rewires itself on every run.
guides/release/in-depth-topics/reactivity/index.md:136
- With the new
@tracked({ equals })form, a write invokes the user-provided equality callback synchronously, so it is no longer true that no user code runs. The pull-based guarantee is specifically that writes do not execute derivations/getters; phrase it in those terms.
Autotracking is pull-based. When you write to a tracked property, no user
code runs at all. Your getters are not re-evaluated; nothing is recomputed.
The write just lets the renderer know that something it consumed is out of
guides/release/in-depth-topics/reactivity/derived-state.md:199
trackedis unused in this example. Keeping the import makes copied code fail the default unused-import lint rule and obscures that a plain function needs no tracking API.
import { tracked } from '@glimmer/tracking';
guides/release/in-depth-topics/reactivity/inputs-and-outputs.md:88
- This chart is canvas-only, so its data has no accessible text representation for screen-reader users. Add an equivalent table/summary or an accessible name and description derived from the chart data; the appropriate representation depends on the data being visualized.
<canvas {{drawChart @chartData}}></canvas>
Advancement PR:
"Overload tracked to work outside of classes"to Stage Ready for Release emberjs/rfcs#1202Merged RFC PR:
trackedto work outside of classes emberjs/rfcs#1071Docs Inspirations:
Read Order: