-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
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 (
|
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.
@danielroe I'm pulling in the
Exampleconst fetchKey = computed((): string => `page-${route.path.replace(/\//g, '-')}`)
const { data } = await useFetch('/api/v3/pages/my-page', {
key: fetchKey,
}) |
@adamdehaven this is expected (from a Nuxt point of view) as the fetch instance is global and never unmounted/cleaned up. You can wrap it in a composable. Or call |
I actually tried calling |
@danielroe Shouldn't this feature also apply to |
@danielroe I believe there is a breaking change regarding FormData handling in fetch.js due to the newly added statement: It originates from ohash. That library cannot hash File objects. if (opts.body) {
segments.push(hash(toValue(opts.body)))
} When I attempt to upload a FormData containing a File in the body, I encounter the following error: const formData = new FormData();
formData.append("image", new_avatar.value);
await useAPI('/company', {
method: 'POST',
body: formData,
}) My current solution is to downgrade v3.16.2 |
There seems to be a breaking change in there as well, on route change without remounting components (via I'm trying to dig what's causing this Okay so after digging, this is entirely due to the key now being computed based on the params This means that if any of the params change the key changes and it switches to another data. But that means there is no data until it's fetched again while before what it would do is keep the previous data but fetch the new one while the previous data was available, this is a problem when you are expecting to always have data via top level A workaround for now seems to be to hardcode a static key |
@danielroe Thank you so much for your work! I'm a little confused by some of the changes to When initially reading about this upgrade to This would typically lead me to the discussions around the fact that This is where I presumed these changes came in attempting to unify the instance returned by However from my testing I'm struggling to understand how this works I have a simple unit test here that illustrates the problem: import type { NuxtApp } from '#app'
import type { AsyncDataRefreshCause } from '#app/composables/asyncData'
import { expect, it, vi } from 'vitest'
const handler = vi.fn(async () => Promise.resolve('hello'))
const getCachedData = vi.fn((key: string, nuxtApp: NuxtApp, ctx: { cause: AsyncDataRefreshCause }) => {
if (nuxtApp.isHydrating) {
return nuxtApp.payload.data[key]
}
const { data } = useNuxtData(key)
if (ctx.cause !== 'refresh:manual' && ctx.cause !== 'refresh:hook' && data.value) {
return data.value
}
})
// eslint-disable-next-line ts/promise-function-async
function testAsyncData() {
return useAsyncData('test-key', handler, {
getCachedData,
})
}
it('test duplicate calls are not made after first call has finished', async () => {
const { status, data } = await testAsyncData()
expect(status.value).toBe('success') // pass
expect(data.value).toBe('hello') // pass
expect(handler).toHaveBeenCalledTimes(1) // pass
const { status: status2, data: data2 } = testAsyncData()
expect.soft(handler).toHaveBeenCalledTimes(1) // fail - called twice
expect.soft(getCachedData).toHaveBeenCalledTimes(2)
expect.soft(data.value).toBe('hello') // pass
expect.soft(data2.value).toBe('hello') // pass
expect.soft(status.value).toBe('success') // fail - value is 'pending'
expect.soft(status2.value).toBe('success') // fail - value is 'pending'
}) Effectively what I am trying to do here is to adjust the default However what actually happens is that whilst the nuxt/packages/nuxt/src/app/composables/asyncData.ts Lines 636 to 645 in ebff42f
It is then used here but it only ever uses the At present it seems to be that we cannot stop the |
🔗 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