Repository navigation
docs: Note Vue's mounted useSuspense keeps data after invalidate - #4411
Conversation
Vue can't re-suspend a mounted component, so useSuspense keeps returning its current data while an invalidated endpoint refetches. Add that carve-out to the invalidate/invalidateAll JSDoc, the useSuspense behavior table, and Controller's ExpiryStatus.Invalid notes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tj5PXbDEpJbnwML9CXTHFb
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tj5PXbDEpJbnwML9CXTHFb
|
Size Change: 0 B Total Size: 112 kB ℹ️ View Unchanged
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cb3a3f65b9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #4411 +/- ##
=======================================
Coverage 98.37% 98.37%
=======================================
Files 161 161
Lines 3072 3072
Branches 604 604
=======================================
Hits 3022 3022
Misses 10 10
Partials 40 40 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Fold the Vue caveat into the invalidate JSDoc's first sentence and point the footnotes at expiry-policy instead of restating the reason. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tj5PXbDEpJbnwML9CXTHFb
|
Docs preview: https://docs-site-pr-4411-data-client.vercel.app Built from 2e6cab7 merged into |
There was a problem hiding this comment.
Benchmark React
Details
| Benchmark suite | Current: 2e6cab7 | Previous: ecac998 | Ratio |
|---|---|---|---|
data-client: getlist-100 |
188.68 ops/s (± 8.9%) |
163.98 ops/s (± 9.1%) |
0.87 |
data-client: getlist-500 |
60.06 ops/s (± 4.5%) |
52.08 ops/s (± 4.2%) |
0.87 |
data-client: update-entity |
357.14 ops/s (± 6.6%) |
370.37 ops/s (± 8.9%) |
1.04 |
data-client: update-user |
434.78 ops/s (± 7.0%) |
434.78 ops/s (± 11.5%) |
1 |
data-client: getlist-500-sorted |
58.15 ops/s (± 8.1%) |
53.91 ops/s (± 6.8%) |
0.93 |
data-client: update-entity-sorted |
327.96 ops/s (± 7.4%) |
384.62 ops/s (± 11.5%) |
1.17 |
data-client: update-entity-multi-view |
327.96 ops/s (± 7.4%) |
384.62 ops/s (± 7.3%) |
1.17 |
data-client: list-detail-switch-10 |
15.4 ops/s (± 8.9%) |
10.62 ops/s (± 9.6%) |
0.69 |
data-client: update-user-10000 |
89.29 ops/s (± 8.9%) |
92.59 ops/s (± 9.4%) |
1.04 |
data-client: invalidate-and-resolve |
49.38 ops/s (± 5.7%) |
42.02 ops/s (± 5.0%) |
0.85 |
data-client: unshift-item |
259.78 ops/s (± 5.4%) |
238.1 ops/s (± 5.4%) |
0.92 |
data-client: delete-item |
370.37 ops/s (± 8.9%) |
312.5 ops/s (± 9.7%) |
0.84 |
data-client: move-item |
208.33 ops/s (± 6.1%) |
190.49 ops/s (± 7.6%) |
0.91 |
This comment was automatically generated by workflow using github-action-benchmark.
There was a problem hiding this comment.
Benchmark
Details
| Benchmark suite | Current: 2e6cab7 | Previous: ecac998 | Ratio |
|---|---|---|---|
normalizeLong |
432 ops/sec (±3.21%) |
548 ops/sec (±4.07%) |
1.27 |
normalizeLong Values |
387 ops/sec (±0.48%) |
470 ops/sec (±0.84%) |
1.21 |
normalizeLong Scalar |
360 ops/sec (±2.92%) |
448 ops/sec (±2.54%) |
1.24 |
normalizeLong Scalar update |
894 ops/sec (±0.16%) |
1103 ops/sec (±0.72%) |
1.23 |
denormalizeLong |
231 ops/sec (±5.46%) |
293 ops/sec (±5.80%) |
1.27 |
denormalizeLong Values |
212 ops/sec (±5.57%) |
274 ops/sec (±4.95%) |
1.29 |
denormalizeLong donotcache |
997 ops/sec (±0.98%) |
1344 ops/sec (±0.92%) |
1.35 |
denormalizeLong Values donotcache |
720 ops/sec (±0.26%) |
954 ops/sec (±0.17%) |
1.32 |
denormalizeLong Scalar donotcache |
1063 ops/sec (±0.30%) |
1541 ops/sec (±0.08%) |
1.45 |
denormalizeShort donotcache 500x |
1418 ops/sec (±0.13%) |
1762 ops/sec (±0.21%) |
1.24 |
denormalizeShort 500x |
623 ops/sec (±7.09%) |
745 ops/sec (±6.15%) |
1.20 |
denormalizeShort 500x withCache |
6262 ops/sec (±0.16%) |
9383 ops/sec (±0.06%) |
1.50 |
queryShort 500x withCache |
3137 ops/sec (±0.81%) |
4221 ops/sec (±0.19%) |
1.35 |
buildQueryKey All |
59716 ops/sec (±0.50%) |
69817 ops/sec (±0.61%) |
1.17 |
query All withCache |
5941 ops/sec (±2.42%) |
7884 ops/sec (±2.64%) |
1.33 |
denormalizeLong with mixin Entity |
208 ops/sec (±7.49%) |
266 ops/sec (±6.47%) |
1.28 |
denormalizeLong withCache |
6195 ops/sec (±0.24%) |
7853 ops/sec (±0.20%) |
1.27 |
denormalizeLong withCache (Scalar churn) |
6170 ops/sec (±1.00%) |
7774 ops/sec (±0.71%) |
1.26 |
denormalizeLong Values withCache |
4732 ops/sec (±1.48%) |
8436 ops/sec (±1.51%) |
1.78 |
denormalizeLong Scalar withCache |
7059 ops/sec (±0.25%) |
9577 ops/sec (±0.20%) |
1.36 |
denormalizeLong Scalar update withCache |
3989 ops/sec (±1.16%) |
7186 ops/sec (±0.56%) |
1.80 |
denormalizeLong All withCache |
6046 ops/sec (±0.35%) |
9149 ops/sec (±0.29%) |
1.51 |
denormalizeLong Query-sorted withCache |
6087 ops/sec (±1.12%) |
8020 ops/sec (±3.69%) |
1.32 |
denormalizeLongAndShort withEntityCacheOnly |
1654 ops/sec (±0.34%) |
1938 ops/sec (±1.28%) |
1.17 |
denormalize bidirectional 50 |
4512 ops/sec (±8.21%) |
5393 ops/sec (±8.70%) |
1.20 |
denormalize bidirectional 50 donotcache |
41771 ops/sec (±0.20%) |
56174 ops/sec (±0.16%) |
1.34 |
getResponse |
4391 ops/sec (±4.19%) |
6386 ops/sec (±4.40%) |
1.45 |
getResponse (null) |
10163053 ops/sec (±0.70%) |
12989177 ops/sec (±0.76%) |
1.28 |
getResponse (clear cache) |
199 ops/sec (±9.21%) |
268 ops/sec (±8.07%) |
1.35 |
getSmallResponse |
3421 ops/sec (±4.14%) |
4939 ops/sec (±1.11%) |
1.44 |
getSmallInferredResponse |
2703 ops/sec (±0.14%) |
3897 ops/sec (±0.08%) |
1.44 |
getResponse Collection |
4438 ops/sec (±3.52%) |
6907 ops/sec (±1.55%) |
1.56 |
get Collection |
2778 ops/sec (±0.19%) |
5587 ops/sec (±0.27%) |
2.01 |
get Query-sorted |
4994 ops/sec (±1.13%) |
7638 ops/sec (±2.31%) |
1.53 |
setLong |
432 ops/sec (±0.60%) |
562 ops/sec (±0.11%) |
1.30 |
setLongWithMerge |
246 ops/sec (±1.04%) |
326 ops/sec (±0.85%) |
1.33 |
setLongWithSimpleMerge |
264 ops/sec (±0.66%) |
345 ops/sec (±0.08%) |
1.31 |
setSmallResponse 500x |
899 ops/sec (±1.66%) |
1116 ops/sec (±1.37%) |
1.24 |
setMany 50x one-per-row |
150 ops/sec (±0.72%) |
164 ops/sec (±0.30%) |
1.09 |
setMany 50 batch |
3619 ops/sec (±0.76%) |
4727 ops/sec (±0.40%) |
1.31 |
setMany 500x one-per-row |
15.2 ops/sec (±0.65%) |
16.7 ops/sec (±0.28%) |
1.10 |
setMany 500 batch |
1390 ops/sec (±3.28%) |
1902 ops/sec (±0.23%) |
1.37 |
This comment was automatically generated by workflow using github-action-benchmark.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tj5PXbDEpJbnwML9CXTHFb
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tj5PXbDEpJbnwML9CXTHFb
Requested by Nathaniel · project thread
Follow-up to the staff comment on #4396.
Motivation
Before: the
invalidate/invalidateAllJSDoc, the useSuspense behavior table and Controller'sExpiryStatus.Invalidnotes said invalidation always suspends, with no Vue exception. In Vue a mounteduseSuspensecan't suspend again after setup (packages/vue/src/consumers/useSuspense.ts), so it keeps returning its current data while the refetch runs.After: all three say so on Vue pages (and in the JSDoc), matching what
Controller#invalidateand the expiry-policy page already said.Solution
Controller.ts: one JSDoc line oninvalidateandinvalidateAll.useSuspense.md: Vue-only footnote 3 on the Invalid row's Suspend cell (:vue[]marker plus a:::vueblock inside the note).Controller.md::vue[]carve-out on "Will always suspend".yarn build:skillsregenerated the three Vue skill references.Docs only, so no changeset.
Generated by Claude Code
Note
Low Risk
Documentation and JSDoc comment changes only; no runtime behavior changes.
Overview
Clarifies that
Controller.invalidate/invalidateAllstill trigger refetches but, in Vue, mounteduseSuspenseconsumers do not re-suspend—they keep showing current data until the refetch finishes. Docs previously implied invalidation always suspends like React.Updates span
Controller.tsJSDoc (and mirrored playground.d.ts),useSuspensebehavior tables (Vue footnote on Invalid + suspend-only-during-setup),ExpiryStatus.Invalidnotes, and a Vue tip on remounting with a newkeyand<Suspense timeout="0">to show the fallback again after invalidate. Agent skill references were regenerated viayarn build:skills.Reviewed by Cursor Bugbot for commit 2e6cab7. Bugbot is set up for automated code reviews on this repo. Configure here.