diff --git a/src/data-fetching_new/defineColadaLoader.spec.ts b/src/data-fetching_new/defineColadaLoader.spec.ts index 9f9f1cad7..478ad415b 100644 --- a/src/data-fetching_new/defineColadaLoader.spec.ts +++ b/src/data-fetching_new/defineColadaLoader.spec.ts @@ -116,6 +116,29 @@ describe( app, } } + + it.todo('avoids refetching fresh data when navigating', async () => { + const query = vi.fn().mockResolvedValue('data') + const useData = defineColadaLoader({ + query, + key: (to) => [to.query.q as string], + }) + + const { router } = singleLoaderOneRoute(useData) + + // same key + await router.push('/fetch?q=1&v=1') + expect(query).toHaveBeenCalledTimes(1) + await router.push('/fetch?q=1&v=2') + expect(query).toHaveBeenCalledTimes(1) + + // different key + await router.push('/fetch?q=2&v=3') + expect(query).toHaveBeenCalledTimes(2) + // already fetched + await router.push('/fetch?q=1&v=4') + expect(query).toHaveBeenCalledTimes(2) + }) }, // fail faster on unresolved promises { timeout: 100 } diff --git a/src/data-fetching_new/defineColadaLoader.ts b/src/data-fetching_new/defineColadaLoader.ts index 49b29220a..4204957e1 100644 --- a/src/data-fetching_new/defineColadaLoader.ts +++ b/src/data-fetching_new/defineColadaLoader.ts @@ -368,11 +368,17 @@ export function defineColadaLoader( } satisfies UseDataLoaderResult // load ensures there is a pending load - const promise = entry.pendingLoad!.then(() => { - // nested loaders might wait for all loaders to be ready before setting data - // so we need to return the staged value if it exists as it will be the latest one - return entry!.staged === STAGED_NO_VALUE ? ext!.data.value : entry!.staged - }) + const promise = entry + .pendingLoad!.then(() => { + // nested loaders might wait for all loaders to be ready before setting data + // so we need to return the staged value if it exists as it will be the latest one + return entry!.staged === STAGED_NO_VALUE + ? ext!.data.value + : entry!.staged + }) + // we only want the error if we are nesting the loader + // otherwise this will end up in "Unhandled promise rejection" + .catch((e) => (parentEntry ? Promise.reject(e) : null)) return Object.assign(promise, useDataLoaderResult) } diff --git a/src/data-fetching_new/defineLoader.ts b/src/data-fetching_new/defineLoader.ts index f54ca8622..7df88a6f1 100644 --- a/src/data-fetching_new/defineLoader.ts +++ b/src/data-fetching_new/defineLoader.ts @@ -305,11 +305,15 @@ export function defineBasicLoader( } satisfies UseDataLoaderResult // load ensures there is a pending load - const promise = entry.pendingLoad!.then(() => { - // nested loaders might wait for all loaders to be ready before setting data - // so we need to return the staged value if it exists as it will be the latest one - return entry!.staged === STAGED_NO_VALUE ? data.value : entry!.staged - }) + const promise = entry + .pendingLoad!.then(() => { + // nested loaders might wait for all loaders to be ready before setting data + // so we need to return the staged value if it exists as it will be the latest one + return entry!.staged === STAGED_NO_VALUE ? data.value : entry!.staged + }) + // we only want the error if we are nesting the loader + // otherwise this will end up in "Unhandled promise rejection" + .catch((e) => (parentEntry ? Promise.reject(e) : null)) return Object.assign(promise, useDataLoaderResult) } diff --git a/tests/data-loaders/tester.ts b/tests/data-loaders/tester.ts index 0f62095f0..34ec0fea3 100644 --- a/tests/data-loaders/tester.ts +++ b/tests/data-loaders/tester.ts @@ -327,6 +327,29 @@ export function testDefineLoader( expect(data.value).toBe(undefined) expect(router.currentRoute.value.path).toBe('/fetch') }) + + it('propagates errors from nested loaders', async () => { + const l1 = mockedLoader({ + key: 'nested', + commit, + lazy: false, + }) + const { wrapper, app, router, useData } = singleLoaderOneRoute( + loaderFactory({ + fn: async (to) => { + const data = await l1.loader() + return `${data},${to.query.p}` + }, + key: 'root', + }) + ) + + const p = router.push('/fetch?p=one') + await vi.runOnlyPendingTimersAsync() + + l1.reject(new Error('nope')) + await expect(p).rejects.toThrow('nope') + }) } )