Skip to content

Commit

Permalink
fix(angular-query-experimental): run mutation callback in injection c…
Browse files Browse the repository at this point in the history
…ontext

Previously, the injectMutation callback was run in injection context only if accessed in the same task as the component initialization (i.e. before the `effect` callback run). By running the effect run in injection context, it is ensured that the callback will always run in injection context, and any `inject` calls will not fail.

Note there is a separate issue here, and it's that the callback is always run twice - once synchronously when initialization the mutation, and secondly as the first callback of the `effect`. This is something that can potentially be improved.

No breaking changes, any code that worked before should still work.
  • Loading branch information
ShacharHarshuv authored and sharshuv-quotient committed May 8, 2024
1 parent 01ce023 commit f34b811
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, input, signal } from '@angular/core'
import { Component, Injectable, inject, input, signal } from '@angular/core'
import { QueryClient } from '@tanstack/query-core'
import { TestBed } from '@angular/core/testing'
import { describe, expect, vi } from 'vitest'
Expand Down Expand Up @@ -455,4 +455,38 @@ describe('injectMutation', () => {

await expect(() => mutateAsync()).rejects.toThrowError(err)
})

test('should execute callback in injection context', async () => {
@Injectable()
class FakeService {
updateData(name: string) {
return Promise.resolve(name)
}
}

@Component({
selector: 'app-fake',
template: ``,
standalone: true,
providers: [FakeService],
})
class FakeComponent {
mutation = injectMutation(() => {
const service = inject(FakeService)
return {
mutationFn: (name: string) => service.updateData(name),
}
})
}

const fixture = TestBed.createComponent(FakeComponent)
fixture.detectChanges()

// check if injection contexts persist in a different task
await new Promise<void>((resolve) => queueMicrotask(() => resolve()))

expect(
await fixture.componentInstance.mutation.mutateAsync('test'),
).toEqual('test')
})
})
4 changes: 3 additions & 1 deletion packages/angular-query-experimental/src/inject-mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ export function injectMutation<
}

effect(() => {
observer.setOptions(optionsFn(queryClient))
observer.setOptions(
runInInjectionContext(currentInjector, () => optionsFn(queryClient)),
)
})

const result = signal(observer.getCurrentResult())
Expand Down

0 comments on commit f34b811

Please sign in to comment.