-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
fix(nuxt): use single synced asyncdata instance per key #31373
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
Conversation
Co-authored-by: Alexander Lichter <github@lichter.io>
|
@nuxt/kit
nuxt
@nuxt/rspack-builder
@nuxt/schema
@nuxt/vite-builder
@nuxt/webpack-builder
commit: |
CodSpeed Performance ReportMerging #31373 will not alter performanceComparing Summary
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Co-authored-by: Damian Głowala <damian.glowala.rebkow@gmail.com>
After this PR, would From my testing, when the Here is the test code I used: <script lang="ts">
const fetch = () => {
return new Promise((resolve) => {
console.log('fetch...')
setTimeout(() => {
resolve('Nuxt Data 1')
}, 1000)
})
}
function useMyAsyncData() {
return useAsyncData('NUXT_DATA', fetch, {
dedupe: 'cancel' // or 'defer'
})
}
</script>
<script setup lang="ts">
const { data: d1 } = useMyAsyncData()
const { data: d2 } = useMyAsyncData()
</script> Would it make sense to default |
WalkthroughThe changes introduce a new experimental configuration option, granularCachedData, which controls whether cached responses from asynchronous data fetching are utilised during refreshes. The function signatures for both 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
⏰ Context from checks skipped due to timeout of 90000ms (1)
🔇 Additional comments (5)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
efa0a80
to
e8659e1
Compare
to investigate: https://stackblitz.com/edit/github-cpgxhnuj?file=package.json |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
docs/3.api/2.composables/use-fetch.md (1)
69-82
: Subject: Clear Explanation of Reactive Keys and Shared State
The new "Reactive Keys and Shared State" section is a well-crafted addition. It clearly demonstrates how to use a computed or plain ref as the URL to enable dynamic data fetching that automatically updates when the key changes. This example should help users quickly grasp this new feature.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
docs/1.getting-started/10.data-fetching.md
(3 hunks)docs/1.getting-started/18.upgrade.md
(1 hunks)docs/2.guide/3.going-further/1.experimental-features.md
(1 hunks)docs/3.api/2.composables/use-async-data.md
(5 hunks)docs/3.api/2.composables/use-fetch.md
(4 hunks)test/basic.test.ts
(0 hunks)test/nuxt/composables.test.ts
(7 hunks)
💤 Files with no reviewable changes (1)
- test/basic.test.ts
🧰 Additional context used
🧬 Code Definitions (1)
test/nuxt/composables.test.ts (3)
packages/nuxt/src/app/composables/asyncData.ts (4)
useAsyncData
(197-389)useNuxtData
(467-489)clearNuxtData
(504-516)refreshNuxtData
(492-501)packages/nuxt/src/app/composables/index.ts (5)
useAsyncData
(2-2)useNuxtData
(2-2)clearNuxtData
(2-2)refreshNuxtData
(2-2)useRoute
(15-15)packages/nuxt/src/app/index.ts (6)
useAsyncData
(4-4)useNuxtApp
(1-1)useNuxtData
(4-4)clearNuxtData
(4-4)refreshNuxtData
(4-4)useRoute
(4-4)
🪛 LanguageTool
docs/2.guide/3.going-further/1.experimental-features.md
[uncategorized] ~624-~624: Loose punctuation mark.
Context: ... granularCachedData: true } }) ``` ::read-more{icon="i-simple-icons-github" ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~626-~626: Loose punctuation mark.
Context: ...e PR #31373 for implementation details. ::
(UNLIKELY_OPENING_PUNCTUATION)
docs/1.getting-started/10.data-fetching.md
[uncategorized] ~354-~354: Loose punctuation mark.
Context: ...eAsyncData` will be generated for you. ::tip To get the cached data by key, you ...
(UNLIKELY_OPENING_PUNCTUATION)
docs/3.api/2.composables/use-fetch.md
[uncategorized] ~84-~84: Loose punctuation mark.
Context: ...ensures consistency across components. ::warning useFetch
is a reserved functi...
(UNLIKELY_OPENING_PUNCTUATION)
docs/1.getting-started/18.upgrade.md
[uncategorized] ~237-~237: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...(Previously, new data was always fetched and this function was not called in these c...
(COMMA_COMPOUND_SENTENCE_2)
docs/3.api/2.composables/use-async-data.md
[uncategorized] ~72-~72: Loose punctuation mark.
Context: ...rById(route.params.id) ) </script> ``` ::warning [useAsyncData
](/docs/api/comp...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~74-~74: Loose punctuation mark.
Context: ...(/docs/api/composables/use-async-data). :: :read-more{to="/docs/getting-started/...
(UNLIKELY_OPENING_PUNCTUATION)
⏰ Context from checks skipped due to timeout of 90000ms (15)
- GitHub Check: test-fixtures (windows-latest, built, vite, default, manifest-off, json, 18)
- GitHub Check: test-fixtures (windows-latest, built, rspack, async, manifest-on, json, 18)
- GitHub Check: test-fixtures (ubuntu-latest, built, webpack, async, manifest-on, json, 18)
- GitHub Check: test-fixtures (ubuntu-latest, built, rspack, async, manifest-on, json, 18)
- GitHub Check: test-fixtures (ubuntu-latest, built, vite, default, manifest-on, json, 18)
- GitHub Check: test-fixtures (windows-latest, dev, vite, async, manifest-off, json, 18)
- GitHub Check: test-fixtures (ubuntu-latest, dev, vite, async, manifest-on, json, 18)
- GitHub Check: test-fixtures (ubuntu-latest, dev, vite, async, manifest-on, js, 18)
- GitHub Check: test-fixtures (ubuntu-latest, built, vite, async, manifest-on, json, 18)
- GitHub Check: test-fixtures (ubuntu-latest, built, vite, async, manifest-on, js, 18)
- GitHub Check: test-fixtures (ubuntu-latest, dev, vite, default, manifest-off, json, 18)
- GitHub Check: release-pr
- GitHub Check: test-benchmark
- GitHub Check: typecheck (windows-latest, bundler)
- GitHub Check: typecheck (ubuntu-latest, bundler)
🔇 Additional comments (32)
docs/2.guide/3.going-further/1.experimental-features.md (1)
613-627
: Well-documented new experimental feature.The addition of the
granularCachedData
configuration option enhances the control over caching behavior in Nuxt's data fetching system. This feature allows developers to specify whether thegetCachedData
function should be called and its result utilised during data refresh operations (via watch, manual refresh or hook-based refresh).The documentation clearly explains the purpose of this feature with appropriate configuration examples. This aligns with the PR objectives of improving the data fetching layer's performance and consistency.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~624-~624: Loose punctuation mark.
Context: ... granularCachedData: true } }) ``` ::read-more{icon="i-simple-icons-github" ...(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~626-~626: Loose punctuation mark.
Context: ...e PR #31373 for implementation details. ::(UNLIKELY_OPENING_PUNCTUATION)
docs/1.getting-started/10.data-fetching.md (3)
59-59
: Improved apostrophe consistency in documentation.Fixed the formatting of the possessive form of "Vue" from "Vue's" to "Vue's".
359-397
: Excellent documentation for shared state behaviour.This new section clearly explains an important change in how
useAsyncData
anduseFetch
share state when using the same key. The documentation properly categorises which options must remain consistent (handler, deep, transform, pick, getCachedData, default) and which can safely differ (server, lazy, immediate, dedupe, watch).The examples effectively demonstrate both valid and invalid usages, helping developers avoid potential issues when sharing data between components. This is a crucial addition that aligns with the PR's objective of ensuring consistency across components using the same data references.
398-413
: Clear documentation for reactive keys feature.The new "Reactive Keys" section effectively explains how developers can now use computed refs or plain refs as keys for dynamic data fetching. The example provided clearly demonstrates how changing a reactive key automatically triggers refetching and proper cleanup of old data.
This feature addresses the dynamic data fetching enhancement mentioned in the PR objectives and provides a more elegant approach to managing related data dependencies.
test/nuxt/composables.test.ts (16)
3-10
: Enhanced import structure for tests.Added
beforeEach
for test setup and includedflushPromises
from Vue test utils to properly handle async operations in the tests. This improves the test structure and enables better handling of component lifecycle events in the new tests.
134-153
: Improved test suite setup with reusable helper function.The addition of a
uniqueKey
variable generated for each test ensures test isolation and prevents test cases from interfering with each other. This is particularly important for testing the new shared state behavior.The
mountWithAsyncData
helper function is a great abstraction that simplifies testing components that useuseAsyncData
. It properly wraps the component mounting process and returns both the component instance and the result ofuseAsyncData
, making the tests more readable and maintainable.
157-167
: Updated expected keys in return value.Added
clear
andstatus
to the expected keys returned byuseAsyncData
, reflecting the enhanced API that now provides more control over the data lifecycle.
187-199
: Updated test to verify shared state behavior.The test now correctly uses the
uniqueKey
to ensure test isolation, and adds verification that callinguseAsyncData
with the same key shares state between instances. This tests the "shared state" feature mentioned in the PR objectives.
211-216
: Improved test isolation with uniqueKey.Updated the test to use the uniqueKey variable instead of hardcoded strings, ensuring that tests don't interfere with each other and properly testing the integration with
useNuxtData
.
220-230
: Enhanced test for useAsyncData after useNuxtData call.The test now uses
uniqueKey
for better isolation and explicitly tests the server-side-only data fetching scenario. This verifies that the data fetching and caching behavior works correctly whenuseNuxtData
is called beforeuseAsyncData
.
234-239
: Better test isolation for refreshNuxtData test.Updated the test to use
uniqueKey
for isolation and explicitly cleared data to ensure the refresh behavior is tested from a clean state.
242-281
: Comprehensive test for overriding requests.This new test verifies that requests can be overridden correctly with the new data fetching system. It thoroughly tests various scenarios:
- Initial hydration state correctly uses payload data
- Requesting data with
dedupe: 'cancel'
starts but doesn't immediately execute the handler- A second refresh completes and updates the value
- The original refresh eventually completes but doesn't affect the value
This test is crucial for ensuring that request deduplication works correctly with the new shared state behavior.
295-339
: Thorough test for status tracking across component lifecycles.This new test verifies that the status of data fetching operations is properly tracked through component mounting, data fetching, and unmounting. It confirms that:
- Status starts as "pending" during fetch
- Transitions to "success" after data is loaded
- Reverts to "idle" when component is unmounted
- Correctly handles remounting and refetching
This test is essential for ensuring that components sharing the same data have consistent loading states, as mentioned in the PR objectives.
341-352
: Test for caching behavior during refreshes.This test verifies that the
getCachedData
function receives the correct context information (specifically the refresh cause) during refreshes triggered by the refresh hook. This is an important part of the new granular caching behavior.
374-403
: Comprehensive tests for granular caching behavior.These three tests thoroughly verify the new caching behavior:
- Using cached data on refresh by default
- Receiving the correct context (cause: 'initial') on initial fetch
- Receiving the correct context (cause: 'refresh:manual') on manual refresh
- Receiving the correct context (cause: 'watch') when a watched dependency changes
These tests are crucial for validating the new
granularCachedData
feature described in the PR objectives.
432-446
: Improved test for dedupe with different keys.Updated the test keys to avoid conflicts with other tests, ensuring proper isolation and more accurate validation of the deduplication feature.
448-482
: Comprehensive tests for option consistency warnings.These new tests verify that appropriate warnings are displayed when incompatible options are used with the same key, including:
- Mismatching
deep
option- Different
transform
function- Different
pick
array- Different
getCachedData
function- Different handler function
This ensures that developers receive clear guidance when they might unintentionally create inconsistent data references across components, which directly addresses the PR objectives regarding consistency.
484-503
: Test for watch call deduplication.This test verifies that when multiple components watch the same data source, watch calls are deduplicated to reduce unnecessary API requests. This directly validates one of the key PR objectives about deduplication of watch calls.
505-527
: Thorough test for reactive keys.This test properly verifies the new reactive keys feature by:
- Using a reactive ref as a key
- Confirming the initial data fetch works correctly
- Changing the key and verifying the data is automatically refetched
- Checking that old data is properly cleaned up when no longer used
- Confirming that new data is correctly stored
This validates a key feature mentioned in the PR objectives about using reactive keys for dynamic data fetching.
529-552
: Test for proper memory cleanup.This test verifies that when the last component using data fetched with
useAsyncData
is unmounted, the data is properly removed from memory. This is important for preventing memory leaks in applications with many components using the same data.The test correctly:
- Mounts multiple components using the same key
- Unmounts them one by one
- Verifies the data remains available until the last component is unmounted
- Confirms the data is completely removed when all components are unmounted
This directly addresses the PR objective regarding memory usage improvements.
docs/1.getting-started/18.upgrade.md (4)
227-236
: Clear migration documentation for data fetching changes.This section effectively introduces the "Singleton Data Fetching Layer" changes, clearly indicating the moderate impact level and explaining the major changes made to Nuxt's data fetching system. The introduction sets proper expectations for users upgrading to the new version.
237-246
: Comprehensive explanation of the data fetching changes.This section clearly explains the four main changes to the data fetching system:
- Shared refs for the same key
- Enhanced control over
getCachedData
- Reactive key support
- Data cleanup
The explanation about the
getCachedData
function now receiving a context object is particularly important for users to understand how to migrate their code.🧰 Tools
🪛 LanguageTool
[uncategorized] ~237-~237: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...(Previously, new data was always fetched and this function was not called in these c...(COMMA_COMPOUND_SENTENCE_2)
247-248
: Clear explanation of motivation for changes.Briefly explains the reasoning behind the changes: improving memory usage and increasing consistency with loading states across calls. This helps users understand why these changes are beneficial.
249-299
: Well-structured migration guidance.This section provides clear, step-by-step migration instructions with:
- Guidance on checking for inconsistent options with example code
- Suggestion to extract shared calls into composables for better consistency
- Examples showing how to update
getCachedData
implementations for the new context parameter- Configuration options to disable the new behavior if needed
The examples are particularly helpful in illustrating both the issues to look for and how to resolve them, making it easier for developers to migrate their applications.
docs/3.api/2.composables/use-fetch.md (2)
130-133
: Subject: Updated getDefaultCachedData Snippet
The revisedgetDefaultCachedData
now accepts the additionalctx
parameter. This enhancement provides more granular control over caching behaviour during hydration versus static rendering. Please ensure that the accompanying documentation and any related examples are updated to reflect this change.
202-205
: Subject: New AsyncDataRequestContext Type Declaration
Introducing theAsyncDataRequestContext
type with itscause
property significantly improves the clarity and safety of the caching strategy by explaining why a data request is being made. This addition helps maintain consistency betweenuseFetch
anduseAsyncData
.docs/3.api/2.composables/use-async-data.md (6)
56-71
: Subject: Clear Reactive Keys Example
The "Reactive Keys" section now shows an excellent example of using a computed ref as the key foruseAsyncData
. This dynamic approach to key management is clear and concise, which should aid users in implementing reactive data fetching effectively.
93-97
: Subject: Updated getDefaultCachedData Snippet
The snippet forgetDefaultCachedData
has been updated to include thectx
parameter. This change enhances cache retrieval decisions by considering the context of the data request (e.g. hydration state). It would be good to ensure consistency in documentation across both composables.
118-136
: Subject: Detailed Shared State and Option Consistency Section
This new section comprehensively details which options must remain consistent when sharing state across multipleuseAsyncData
calls. The inclusion of examples demonstrating both compliant and non-compliant scenarios reinforces best practices. Note that this guidance mirrors earlier reviews, so please verify that the updated documentation does not conflict with previous guidance.
170-178
: Subject: Updated Function Signature for Reactive Keys
Expanding thekey
parameter to acceptRef<string>
andComputedRef<string>
greatly increases flexibility for dynamic data fetching. This update is forward-thinking and aligns well with modern Vue practices.
189-191
: Subject: Enhanced getCachedData Option in AsyncDataOptions
Including thectx
parameter in thegetCachedData
function signature standardises caching behaviour betweenuseAsyncData
anduseFetch
. This update should help developers implement more robust caching logic based on the request’s context.
193-196
: Subject: New AsyncDataRequestContext Type
The addition of theAsyncDataRequestContext
type, featuring thecause
property, provides critical context for data requests. This improvement supports clearer debugging and more predictable cache handling.
Will this fix the issue where useFetch does not work with a reactive key as in the issue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
docs/1.getting-started/18.upgrade.md (1)
273-288
: Consider adding code comments for clarity in the diff exampleWhile the diff example for updating
getCachedData
is good, it would be helpful to add more inline comments explaining what each case ofctx.cause
represents and when it might be useful to handle differently.useAsyncData('key', fetchFunction, { - getCachedData: (key, nuxtApp) => { - return cachedData[key] - } + getCachedData: (key, nuxtApp, ctx) => { + // ctx.cause - can be 'initial' | 'refresh:hook' | 'refresh:manual' | 'watch' + + // Example: Don't use cache on manual refresh + if (ctx.cause === 'refresh:manual') return undefined + + // Example: Use different caching strategy for watch-triggered refreshes + if (ctx.cause === 'watch') { + // Custom watch caching logic + } + + return cachedData[key] + } })docs/3.api/2.composables/use-fetch.md (1)
83-83
: Spacing issue after the sentenceThere's an extra space before the
::warning
directive which could affect rendering.-When using `useFetch` with the same URL and options in multiple components, they will share the same `data`, `error` and `status` refs. This ensures consistency across components. +When using `useFetch` with the same URL and options in multiple components, they will share the same `data`, `error` and `status` refs. This ensures consistency across components.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
docs/1.getting-started/10.data-fetching.md
(3 hunks)docs/1.getting-started/18.upgrade.md
(1 hunks)docs/2.guide/3.going-further/1.experimental-features.md
(1 hunks)docs/3.api/2.composables/use-async-data.md
(5 hunks)docs/3.api/2.composables/use-fetch.md
(4 hunks)packages/nuxt/src/app/composables/asyncData.ts
(17 hunks)packages/nuxt/src/app/composables/fetch.ts
(1 hunks)packages/schema/src/config/experimental.ts
(1 hunks)test/fixtures/basic-types/types.ts
(1 hunks)test/nuxt/composables.test.ts
(8 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/schema/src/config/experimental.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
test/nuxt/composables.test.ts (4)
packages/nuxt/src/app/composables/asyncData.ts (4)
useAsyncData
(197-389)useNuxtData
(493-515)clearNuxtData
(530-542)refreshNuxtData
(518-527)packages/nuxt/src/app/composables/index.ts (5)
useAsyncData
(2-2)useNuxtData
(2-2)clearNuxtData
(2-2)refreshNuxtData
(2-2)useRoute
(15-15)packages/nuxt/src/app/nuxt.ts (1)
useNuxtApp
(539-552)packages/nuxt/src/app/composables/router.ts (1)
useRoute
(20-28)
test/fixtures/basic-types/types.ts (1)
packages/nuxt/src/app/composables/asyncData.ts (2)
useAsyncData
(197-389)useLazyAsyncData
(472-490)
🪛 LanguageTool
docs/1.getting-started/18.upgrade.md
[uncategorized] ~237-~237: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...(Previously, new data was always fetched and this function was not called in these c...
(COMMA_COMPOUND_SENTENCE_2)
docs/1.getting-started/10.data-fetching.md
[uncategorized] ~354-~354: Loose punctuation mark.
Context: ...eAsyncData` will be generated for you. ::tip To get the cached data by key, you ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~358-~358: Loose punctuation mark.
Context: ...docs/api/composables/use-nuxt-data) :: :video-accordion{title="Watch a video fro...
(UNLIKELY_OPENING_PUNCTUATION)
docs/2.guide/3.going-further/1.experimental-features.md
[uncategorized] ~620-~620: Loose punctuation mark.
Context: ... granularCachedData: true } }) ``` ::read-more{icon="i-simple-icons-github" ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~622-~622: Loose punctuation mark.
Context: ...e PR #31373 for implementation details. ::
(UNLIKELY_OPENING_PUNCTUATION)
docs/3.api/2.composables/use-async-data.md
[uncategorized] ~72-~72: Loose punctuation mark.
Context: ...rById(route.params.id) ) </script> ``` ::warning [useAsyncData
](/docs/api/comp...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~74-~74: Loose punctuation mark.
Context: ...(/docs/api/composables/use-async-data). :: :read-more{to="/docs/getting-started/...
(UNLIKELY_OPENING_PUNCTUATION)
docs/3.api/2.composables/use-fetch.md
[uncategorized] ~84-~84: Loose punctuation mark.
Context: ...ensures consistency across components. ::warning useFetch
is a reserved functi...
(UNLIKELY_OPENING_PUNCTUATION)
🔇 Additional comments (45)
docs/2.guide/3.going-further/1.experimental-features.md (1)
609-623
: Well-documented new experimental feature.The addition of the
granularCachedData
feature is clearly explained with both its purpose and usage example. This feature provides more control over data fetching behavior by allowing the result fromgetCachedData
to be utilized during refresh operations.The code example is straightforward and follows the established pattern of other experimental features in this document. The inclusion of a link to the GitHub PR for implementation details provides valuable context for developers who want to understand the inner workings.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~620-~620: Loose punctuation mark.
Context: ... granularCachedData: true } }) ``` ::read-more{icon="i-simple-icons-github" ...(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~622-~622: Loose punctuation mark.
Context: ...e PR #31373 for implementation details. ::(UNLIKELY_OPENING_PUNCTUATION)
packages/nuxt/src/app/composables/fetch.ts (2)
100-103
: Enhanced key reactivity for dynamic data fetching.The key computation has been wrapped in a
computed()
function, making it reactive to changes in its dependencies. This allows for more dynamic behavior when using reactive URL parameters or other changing values. The error handling has also been updated accordingly to check_key.value
.This change is crucial for the reactive keys feature, allowing the composable to respond to changes in the key's dependencies and automatically refetch data when needed.
108-108
: Reactive key computation for consistent behavior.The key variable is now also made reactive through
computed()
, ensuring it stays in sync with the_key
value. This maintains the special prefixing logic ($f
) for automatically generated keys while preserving reactivity.This change ensures that the internal key tracking remains consistent when using reactive keys.
test/fixtures/basic-types/types.ts (2)
548-552
: Good type tests for computed key support in useAsyncData.These tests verify that
useAsyncData
correctly handles computed properties as keys. The expectTypeOf assertions ensure that the function's return type is properly inferred even when using a computed key instead of a string literal.This ensures type safety when developers use the new reactive key functionality.
553-556
: Type tests for computed key support in useLazyAsyncData.Similar to the tests for
useAsyncData
, these assertions verify thatuseLazyAsyncData
properly handles computed property keys with correct type inference.These tests are important to ensure consistent behavior between the eager and lazy variants of the composable.
docs/1.getting-started/10.data-fetching.md (3)
59-59
: Minor grammatical fix.Corrected possessive apostrophe in "Vue's".
361-398
: Clear documentation on shared state and option consistency.This new section clearly explains how multiple components using the same key will share state, which is crucial information for developers. The documentation helpfully categorizes which options must be consistent across calls with the same key and which can safely differ.
The examples show both incorrect usage that will trigger warnings and correct patterns, providing practical guidance for developers.
400-415
: Excellent documentation on reactive keys feature.This section explains the new ability to use computed refs, plain refs, or getter functions as keys, enabling dynamic data fetching. The example clearly demonstrates how data can be automatically refetched when dependencies change.
This is a powerful addition that makes data fetching more flexible and reactive, aligning with Vue's reactive programming model.
test/nuxt/composables.test.ts (12)
134-139
: Well structured test isolation with uniqueKeyAdding a unique key generator for each test ensures proper isolation between test cases and prevents test interference when using the same keys across tests.
141-153
: Great helper function for testing async dataThe
mountWithAsyncData
function is a valuable testing utility that encapsulates the complexity of mounting components with async data handling. It returns both the component instance and async data result, making tests more readable and maintainable.
195-206
: Confirms expected shared state behaviorThis test correctly verifies that multiple calls to
useAsyncData
with the same key share the same refs, which is a key feature of the new singleton data fetching layer. It also tests the warning that appears when incompatible options are used.
249-288
: Comprehensive test for request overridingThis test thoroughly validates the request prioritization behavior when overriding requests. It ensures that:
- Initial data from payload is respected
- Cancellation works with the
dedupe: 'cancel'
option- New requests properly update the shared data
The sequence of test steps effectively demonstrates the intended behavior.
302-346
: Validates status lifecycle for async requestsGood test coverage of the status transitions (idle → pending → success) throughout the component lifecycle, including unmounting scenarios. This ensures the
status
ref is accurately maintained.
348-359
: Tests cache refresh behavior with contextThis test verifies that
getCachedData
receives the proper context information during refreshes. It confirms the context contains the correctcause
value for refresh operations triggered by hooks.
381-386
: Verifies cache usage on refreshGood test to confirm the default behavior of using cache on refresh, ensuring that fetched data respects the cached value returned by
getCachedData
.
388-410
: Validates context parameter in different scenariosThese tests thoroughly check that the
getCachedData
function receives the correctcause
value in different scenarios:
- Initial fetch
- Manual refresh
- Watch-triggered refresh
This ensures the context parameter works correctly in all relevant cases.
455-490
: Comprehensive testing of option consistency warningsExcellent coverage of the warning system for incompatible options. The test validates warnings for different incompatible options (
deep
,transform
,pick
,getCachedData
, and handler function differences) ensuring users get proper guidance when mixing configurations with the same key.
493-512
: Tests for watch deduplicated refreshesThis test confirms that when a watched dependency changes,
useAsyncData
only refreshes once, preventing redundant API calls. This is crucial for performance when multiple components watch the same data source.
514-547
: Validates reactive key supportThis test thoroughly checks the reactive key functionality with both ref and getter approaches. It verifies that:
- Data is refetched when the key changes
- Previous data is properly cleaned up
- The payload correctly reflects the current key's data
Great coverage of this important new feature.
549-572
: Validates memory cleanup on component unmountThis test ensures that when the last component using a particular key is unmounted, the associated data is cleaned up. This is important to prevent memory leaks in applications with many components and data fetches.
docs/1.getting-started/18.upgrade.md (2)
227-246
: Clearly explains the major data fetching changesThis section provides a high-level overview of the significant changes to Nuxt's data fetching system. The impact level classification as "Moderate" is appropriate given the scope of changes.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~237-~237: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...(Previously, new data was always fetched and this function was not called in these c...(COMMA_COMPOUND_SENTENCE_2)
247-299
: Excellent migration guide with clear examplesThe migration steps are well-documented with practical examples that illustrate:
- How to extract shared data fetching into composables for consistency
- How to update
getCachedData
implementations to handle the new context parameter- Configuration options to disable new behaviors if needed
This provides users with a clear path forward when upgrading.
docs/3.api/2.composables/use-fetch.md (2)
69-84
: Well-explained reactive keys and shared state featuresThe new section clearly explains how to use computed refs or plain refs as dynamic URLs, which is a powerful feature for data fetching that updates automatically with route changes. The shared state explanation is concise and clear.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~84-~84: Loose punctuation mark.
Context: ...ensures consistency across components. ::warninguseFetch
is a reserved functi...(UNLIKELY_OPENING_PUNCTUATION)
189-201
: Updated signature and added context typeThe updated
getCachedData
signature with the new context parameter aligns with the implementation changes. TheAsyncDataRequestContext
type is well-documented with clear descriptions of the possible causes.docs/3.api/2.composables/use-async-data.md (4)
56-72
: Clear explanation of reactive keys with exampleThis section provides a good explanation of how reactive keys work, with a practical example using route parameters. The explanation makes it clear that data will be automatically refetched when the key changes.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~72-~72: Loose punctuation mark.
Context: ...rById(route.params.id) ) </script> ``` ::warning [useAsyncData
](/docs/api/comp...(UNLIKELY_OPENING_PUNCTUATION)
116-144
: Comprehensive explanation of shared state rulesThis section does an excellent job explaining the shared state behavior and clearly outlines which options must be consistent across calls with the same key and which ones can differ. The examples for both valid and invalid cases provide clear guidance to users.
173-173
: Updated function signature to support reactive keysThe function signature now correctly reflects the support for ref and computed ref keys, which is consistent with the new reactive keys feature described in the documentation.
188-194
: Updated signature and added context typeThe
getCachedData
function signature has been properly updated with the context parameter, and theAsyncDataRequestContext
type is well-documented. This ensures type safety when implementing custom cache strategies based on the fetch cause.packages/nuxt/src/app/composables/asyncData.ts (17)
44-44
: Well-defined type for refresh causesThe new
AsyncDataRefreshCause
type clearly categorizes the different scenarios that trigger data refreshing, enabling more nuanced caching behavior based on the refresh context.
71-71
: Enhanced getCachedData signature with context parameterThe updated signature now includes a context object with the refresh cause, allowing for more intelligent caching decisions based on why the data is being refreshed.
175-175
: Support for reactive keysConverting the key parameter from
string
toMaybeRefOrGetter<string>
enables dynamic data fetching with reactive keys, a significant improvement that allows components to share the same underlying data even when keys are computed.Also applies to: 193-193, 449-449, 467-467
205-205
: Key validation logic for reactive keysThe updated signature handling now correctly supports both string literals and reactive values, with proper type checking that ensures keys are always strings when resolved.
Also applies to: 211-212
224-232
: Improved cached data retrieval logicThe default implementation of
getCachedData
now intelligently handles different refresh causes, only using static data when appropriate (not during manual refreshes or hook-triggered ones).
249-271
: Option consistency validationThis new check warns developers when using the same key with inconsistent options or handlers, preventing subtle bugs that could arise from conflicting configurations.
275-276
: Shared asyncData instance for same keyCreating a single shared instance for each unique key ensures consistent state across components, addressing the issues mentioned in PR objectives around state synchronization.
278-278
: Resource cleanup with dependency trackingThe dependency counter and unregister mechanism ensure proper cleanup of resources when components are unmounted, preventing memory leaks while preserving shared state when needed.
Also applies to: 338-350
332-332
: Deduplication of watch executionUsing the shared async data instance for watch callbacks ensures that multiple components watching the same data with the same key won't trigger duplicate API requests, solving one of the key issues mentioned in the PR objectives.
353-364
: Key change handlingThis watch mechanism elegantly handles reactive key changes by cleaning up old keys and initializing new ones, maintaining proper dependency tracking throughout key changes.
374-382
: State synchronization with writableComputedRefUsing computed refs to maintain connections to the shared state ensures that all components using the same key will always see the same data, errors, and status - even if the key changes.
384-386
: Promise handling improvementsThe promise handling has been improved to ensure that awaiting on asyncData returns the correct references even after key changes, maintaining backward compatibility.
391-400
: Utility for writable computed refsThis helper function creates computed refs that maintain a bidirectional connection to the underlying shared state, enabling both reading and writing to the shared data.
577-578
: Encapsulated async data creationThe new
createAsyncData
function cleanly encapsulates all the logic for creating and managing async data instances, separating concerns and making the code more maintainable.Also applies to: 581-695
619-627
: Enhanced caching behaviorThe implementation now checks for cached data with appropriate context, supporting the new
granularCachedData
configuration option mentioned in the summary, which gives more control over when cached responses are used.
683-683
: Debounced executionThe debounced execution function prevents excessive calls when multiple components trigger the same data fetch simultaneously, addressing performance concerns mentioned in the PR objectives.
697-704
: Hash-based option comparisonThe hash function creates consistent identifiers for handlers and options, enabling reliable comparison of configuration to detect inconsistencies when using the same key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
docs/2.guide/3.going-further/1.experimental-features.md (1)
609-624
: Refine Punctuation and Consistency in "granularCachedData" SectionThe new "granularCachedData" section is very informative and clearly explains the feature. However, please review the punctuation around lines 620–622—as static analysis hints suggest there are some loose punctuation marks—to ensure consistent and clear formatting throughout the documentation.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~620-~620: Loose punctuation mark.
Context: ... granularCachedData: true } }) ``` ::read-more{icon="i-simple-icons-github" ...(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~622-~622: Loose punctuation mark.
Context: ...e PR #31373 for implementation details. ::(UNLIKELY_OPENING_PUNCTUATION)
docs/1.getting-started/18.upgrade.md (1)
249-256
: Clarify Inconsistent Options Migration StepThe migration step addressing potential inconsistencies when using the same key with different options is clearly demonstrated by the example. It might be helpful to emphasise to developers why maintaining consistency in options (such as
deep
,transform
, etc.) is critical, to prevent unexpected warnings.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
docs/1.getting-started/18.upgrade.md
(1 hunks)docs/2.guide/3.going-further/1.experimental-features.md
(1 hunks)packages/schema/src/config/experimental.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/schema/src/config/experimental.ts
🧰 Additional context used
🪛 LanguageTool
docs/1.getting-started/18.upgrade.md
[uncategorized] ~238-~238: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...(Previously, new data was always fetched and this function was not called in these c...
(COMMA_COMPOUND_SENTENCE_2)
docs/2.guide/3.going-further/1.experimental-features.md
[uncategorized] ~620-~620: Loose punctuation mark.
Context: ... granularCachedData: true } }) ``` ::read-more{icon="i-simple-icons-github" ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~622-~622: Loose punctuation mark.
Context: ...e PR #31373 for implementation details. ::
(UNLIKELY_OPENING_PUNCTUATION)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: release-pr
- GitHub Check: codeql (javascript-typescript)
🔇 Additional comments (9)
docs/1.getting-started/18.upgrade.md (9)
228-242
: Singleton Data Fetching Layer: Overview and ImpactThe newly introduced "Singleton Data Fetching Layer" section effectively outlines the key changes, including shared refs for identical keys, improved control over the caching function via an updated signature, reactive key support, and automatic data cleanup. This provides users with a solid understanding of the performance and consistency improvements.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~238-~238: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...(Previously, new data was always fetched and this function was not called in these c...(COMMA_COMPOUND_SENTENCE_2)
273-288
: Update togetCachedData
SignatureThe diff showing the update of the
getCachedData
function signature—adding the newctx
parameter and checking for a manual refresh viactx.cause
—is clear and precise. This change provides a more granular caching strategy, and the inline comment enhances understanding.
290-299
: Alternative Configuration for Caching BehaviourProviding an alternative configuration snippet to disable the new caching behaviour (via
granularCachedData
andpurgeCachedData
) is very useful for users who may prefer previous behaviours. The instructions make it clear how to revert the changes if necessary.
320-325
: Update Route Metadata AccessThe diff example that changes the access from
route.meta.name
toroute.name
succinctly addresses the modifications in how route metadata is exposed. This simplification is in line with the updated Nuxt architecture and should reduce ambiguity.
477-487
: Simplify Handling oferror.data
Replacing manual JSON parsing of
error.data
with direct assignment clarifies the intent and reduces potential parsing errors. This improvement also aligns with the updated error handling strategy, where the error object now provides pre-parsed data.
669-678
: Replace Boolean Values fordedupe
OptionThe diff replacing boolean values with explicit string values (
'cancel'
and'defer'
) for thededupe
option improves clarity significantly. This change removes the ambiguity associated with using true/false values and makes the API behaviour more predictable.
769-776
: Ensure Absolute Watch Paths for Builder HooksThe added logic using
relative
andresolve
from Node’sfs
module ensures that paths emitted in thebuilder:watch
hook are absolute with respect to the project’s source directory. This update enhances compatibility with layered architectures and complex projects.
797-799
: Transition from Globalwindow.__NUXT__
AccessSwitching from using the global
window.__NUXT__
object to accessing Nuxt payload viauseNuxtApp().payload
is a commendable update. This move promotes better separation of concerns and supports multi-app patterns, aligning with modern Nuxt practices.
860-867
: Revise Template Compilation withgetContents
The refactoring of template compilation—moving from a static
src
reference to a dynamicgetContents
function that utilises a template utility fromes-toolkit/compat
—is a robust improvement. This approach not only enhances flexibility but also addresses security concerns associated with using lodash’s template function at build time.
🔗 Linked issue
resolves #21532
resolves #24332 and therefore closes #25850
resolves #22348
resolves #27552
resolves #23522 and therefore closes #23993
resolves #27204
resolves #26733
partly implements #15438
📚 Description
This PR is a major reorganisation of the data fetching layer in Nuxt, providing performance/memory improvements + increased consistency.
1.
getCachedData
behavior changeThe
getCachedData
option now:watch
orrefreshNuxtData
cause
property🐞 Bug Fixes
1. Shared refs for the same key
All calls to
useAsyncData
oruseFetch
with the same key will now share not just the underlying data but alsodata
,error
, andstatus
refs. This ensures consistency across components but may affect code that expected isolated instances.2. Warnings for inconsistent options
Multiple calls to
useAsyncData
with the same key but different options will now trigger development warnings. The following options must be consistent across all calls with the same key:handler
functiondeep
optiontransform
functionpick
arraygetCachedData
functiondefault
valueThe following options can differ without triggering warnings:
server
lazy
immediate
dedupe
watch
✨ New Features
1. Reactive keys
You can now use computed refs, plain refs or getter functions as keys, allowing for dynamic data fetching that automatically updates when dependencies change:
2. Deduped watch calls
Multiple components watching the same data source (like route changes) will now trigger only a single data refetch:
🔄 Migration Guide
For getCachedData users
If you were using
getCachedData
, update your implementation to handle the new context parameter:Alternatively, for now, you can disable this behaviour with:
For duplicate key users
If you were intentionally using the same key in multiple places:
🧪 Testing Recommendations
When updating to this version:
🚧 TODO
getCachedData