Skip to content

Commit

Permalink
feat(250): all axios-hooks-generated requests cancel each other
Browse files Browse the repository at this point in the history
fixes #250

This will make it possible to pass the refetch function down to children component and let them
invoke it, without erroring on a missing token.

New behavior: cancelation errors are thrown for requests generated by the `refetch` function.
This is more consistent with how response and other errors are returned when fetching manually.
  • Loading branch information
simoneb committed Jun 21, 2020
1 parent 66c2fbd commit d80067b
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 15 deletions.
3 changes: 0 additions & 3 deletions .versionrc.json

This file was deleted.

2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 25 additions & 10 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,10 @@ export function makeUseAxios(configurationOptions) {
dispatch({ type: actions.REQUEST_END, payload: response })
return response
} catch (err) {
if (StaticAxios.isCancel(err)) {
return
if (!StaticAxios.isCancel(err)) {
dispatch({ type: actions.REQUEST_END, payload: err, error: true })
}

dispatch({ type: actions.REQUEST_END, payload: err, error: true })
throw err
}
}
Expand Down Expand Up @@ -171,29 +170,45 @@ export function makeUseAxios(configurationOptions) {
)
}

React.useEffect(() => {
cancelSourceRef.current = StaticAxios.CancelToken.source()
const cancelOutstandingRequest = React.useCallback(() => {
if (cancelSourceRef.current) {
cancelSourceRef.current.cancel()
}
}, [])

const withCancelToken = React.useCallback(
config => {
cancelOutstandingRequest()

cancelSourceRef.current = StaticAxios.CancelToken.source()

config.cancelToken = cancelSourceRef.current.token

return config
},
[cancelOutstandingRequest]
)

React.useEffect(() => {
if (!options.manual) {
executeRequest(
{ cancelToken: cancelSourceRef.current.token, ...config },
withCancelToken(config),
options,
dispatch
).catch(() => {})
}

return () => cancelSourceRef.current.cancel()
return cancelOutstandingRequest
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [stringifiedConfig])

const refetch = React.useCallback(
(configOverride, options) => {
return executeRequest(
{
cancelToken: cancelSourceRef.current.token,
withCancelToken({
...config,
...configOverride
},
}),
{ useCache: false, ...options },
dispatch
)
Expand Down
15 changes: 14 additions & 1 deletion test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ beforeEach(() => {

afterEach(() => {
// assert that no errors were logged during tests
expect(errors.length).toBe(0)
expect(errors).toEqual([])
})

describe('useAxiosStatic', () => {
Expand Down Expand Up @@ -342,6 +342,19 @@ function standardTests(useAxios, configure, resetConfigure) {

await waitForNextUpdate()
})

it('should throw an error when the request is canceled', async () => {
const cancellation = new Error('canceled')

axios.mockRejectedValueOnce(cancellation)
axios.isCancel = jest
.fn()
.mockImplementationOnce(err => err === cancellation)

const { result } = renderHook(() => useAxios('', { manual: true }))

expect(() => act(result.current[1])).rejects.toBe(cancellation)
})
})
})

Expand Down

0 comments on commit d80067b

Please sign in to comment.