From 9002ee6846efe04f22f4453b5dadda23a67d5f1d Mon Sep 17 00:00:00 2001 From: okxint Date: Sat, 22 Aug 2026 15:59:12 +0530 Subject: [PATCH] fix(svelte-query): useMutationState array never shrank when mutations stopped matching filter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Object.assign copies enumerable own properties but never sets Array.length. When nextResult was shorter than result (fewer mutations matched the filter), trailing stale entries were never removed — the array only ever grew. Fix: replace Object.assign with result.splice(0, result.length, ...nextResult). splice keeps the reactive $state array reference intact (required by Svelte 5 runes) while correctly adjusting length, adding, and removing elements. Adds a regression test: two pending mutations, both settle, assert the filtered result shrinks to []. Fixes #11152 Co-Authored-By: Claude Sonnet 4.6 --- .../fix-svelte-use-mutation-state-shrink.md | 5 ++ .../src/useMutationState.svelte.ts | 2 +- .../useMutationState.svelte.test.ts | 51 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 .changeset/fix-svelte-use-mutation-state-shrink.md diff --git a/.changeset/fix-svelte-use-mutation-state-shrink.md b/.changeset/fix-svelte-use-mutation-state-shrink.md new file mode 100644 index 00000000000..17bcb2996fb --- /dev/null +++ b/.changeset/fix-svelte-use-mutation-state-shrink.md @@ -0,0 +1,5 @@ +--- +"@tanstack/svelte-query": patch +--- + +fix(svelte-query): use splice in useMutationState so the result array shrinks when mutations no longer match the filter diff --git a/packages/svelte-query/src/useMutationState.svelte.ts b/packages/svelte-query/src/useMutationState.svelte.ts index b92c900e8cf..215956b7628 100644 --- a/packages/svelte-query/src/useMutationState.svelte.ts +++ b/packages/svelte-query/src/useMutationState.svelte.ts @@ -44,7 +44,7 @@ export function useMutationState< getResult(mutationCache, options), ) if (result !== nextResult) { - Object.assign(result, nextResult) + result.splice(0, result.length, ...nextResult) } }) diff --git a/packages/svelte-query/tests/useMutationState/useMutationState.svelte.test.ts b/packages/svelte-query/tests/useMutationState/useMutationState.svelte.test.ts index 703c05df631..77bb1134b5f 100644 --- a/packages/svelte-query/tests/useMutationState/useMutationState.svelte.test.ts +++ b/packages/svelte-query/tests/useMutationState/useMutationState.svelte.test.ts @@ -157,3 +157,54 @@ describe('useMutationState', () => { expect(rendered.getByText('Data: ["success"]')).toBeInTheDocument() }) }) + +describe('useMutationState - array shrinks when mutations no longer match filter', () => { + let queryClient: QueryClient + + beforeEach(() => { + vi.useFakeTimers() + queryClient = new QueryClient() + }) + + afterEach(() => { + queryClient.clear() + vi.useRealTimers() + }) + + it('should remove mutations that no longer match the filter', async () => { + const firstKey = queryKey() + const secondKey = queryKey() + const mutationFn = vi.fn(() => sleep(10).then(() => 'data')) + + const rendered = render(Base, { + props: { + queryClient, + successMutationOpts: () => ({ + mutationKey: firstKey, + mutationFn, + }), + errorMutationOpts: () => ({ + mutationKey: secondKey, + mutationFn, + }), + mutationStateOpts: { + filters: { status: 'pending' }, + }, + }, + }) + + fireEvent.click(rendered.getByRole('button', { name: /Success/i })) + fireEvent.click(rendered.getByRole('button', { name: /Error/i })) + + await vi.advanceTimersByTimeAsync(0) + expect( + rendered.getByText('Data: ["pending","pending"]'), + ).toBeInTheDocument() + + await vi.advanceTimersByTimeAsync(10) + + // Both mutations settled — zero now match status: 'pending' + // Previously Object.assign never shrank the array so this stayed ["pending","pending"] + expect(rendered.getByText('Data: []')).toBeInTheDocument() + }) +})