mirror of
https://github.com/simoneb/axios-hooks.git
synced 2025-12-08 21:25:56 +00:00
Merge branch 'master' into reset-loading-on-manual-cancel
This commit is contained in:
commit
8688277d5e
19
CHANGELOG.md
19
CHANGELOG.md
@ -2,6 +2,25 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## [2.5.0-0](https://github.com/simoneb/axios-hooks/compare/v2.4.1...v2.5.0-0) (2021-03-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* no config serialization ([15fe158](https://github.com/simoneb/axios-hooks/commit/15fe1588448fc58b0b5b83815cc3a12812a466a2))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* tests ([4176d94](https://github.com/simoneb/axios-hooks/commit/4176d9489085febda797dabddb104141197a901c))
|
||||
|
||||
### [2.4.1](https://github.com/simoneb/axios-hooks/compare/v2.4.0...v2.4.1) (2021-03-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* regression in config serialization ([c5e8645](https://github.com/simoneb/axios-hooks/commit/c5e86450811b64e1babdd2cff97ad463b5ee83b2))
|
||||
|
||||
## [2.4.0](https://github.com/simoneb/axios-hooks/compare/v2.4.0-0...v2.4.0) (2021-03-05)
|
||||
|
||||
|
||||
|
||||
7
package-lock.json
generated
7
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "axios-hooks",
|
||||
"version": "2.4.0",
|
||||
"version": "2.5.0-0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -6704,6 +6704,11 @@
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
||||
"dev": true
|
||||
},
|
||||
"dequal": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz",
|
||||
"integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug=="
|
||||
},
|
||||
"detect-indent": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "axios-hooks",
|
||||
"version": "2.4.0",
|
||||
"version": "2.5.0-0",
|
||||
"description": "axios-hooks",
|
||||
"keywords": [
|
||||
"axios",
|
||||
@ -34,6 +34,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.13.9",
|
||||
"dequal": "2.0.2",
|
||||
"lru-cache": "6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
31
src/index.js
31
src/index.js
@ -1,6 +1,7 @@
|
||||
import React from 'react'
|
||||
import StaticAxios from 'axios'
|
||||
import LRU from 'lru-cache'
|
||||
import { dequal as deepEqual } from 'dequal/lite'
|
||||
|
||||
const actions = {
|
||||
REQUEST_START: 'REQUEST_START',
|
||||
@ -53,7 +54,7 @@ function configToObject(config) {
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
return Object.assign({}, config)
|
||||
}
|
||||
|
||||
export function makeUseAxios(configureOptions) {
|
||||
@ -217,13 +218,17 @@ export function makeUseAxios(configureOptions) {
|
||||
)
|
||||
}
|
||||
|
||||
function useAxios(_config, options) {
|
||||
const config = React.useMemo(() => configToObject(_config), [_config])
|
||||
|
||||
options = React.useMemo(
|
||||
() => ({ ...defaultOptions, ...options }),
|
||||
function useAxios(_config, _options) {
|
||||
const config = React.useMemo(
|
||||
() => configToObject(_config),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[JSON.stringify(options)]
|
||||
useDeepCompareMemoize(_config)
|
||||
)
|
||||
|
||||
const options = React.useMemo(
|
||||
() => ({ ...defaultOptions, ..._options }),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
useDeepCompareMemoize(_options)
|
||||
)
|
||||
|
||||
const isCancelledManually = React.useRef(false)
|
||||
@ -307,3 +312,15 @@ export function makeUseAxios(configureOptions) {
|
||||
return [state, refetch, cancelManually]
|
||||
}
|
||||
}
|
||||
|
||||
function useDeepCompareMemoize(value) {
|
||||
const ref = React.useRef()
|
||||
const signalRef = React.useRef(0)
|
||||
|
||||
if (!deepEqual(value, ref.current)) {
|
||||
ref.current = value
|
||||
signalRef.current += 1
|
||||
}
|
||||
|
||||
return [signalRef.current]
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ describe('makeUseAxios', () => {
|
||||
|
||||
const setup = makeSetup(makeUseAxios({ axios: mockAxios }))
|
||||
|
||||
const { waitForNextUpdate } = setup()
|
||||
const { waitForNextUpdate } = setup('')
|
||||
|
||||
expect(mockAxios).toHaveBeenCalled()
|
||||
|
||||
@ -83,7 +83,7 @@ describe('makeUseAxios', () => {
|
||||
it('should use local state across rerenders', async () => {
|
||||
axios.mockResolvedValueOnce({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate, rerender } = setup()
|
||||
const { waitForNextUpdate, rerender } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -95,13 +95,13 @@ describe('makeUseAxios', () => {
|
||||
it('should hit network across component mounts', async () => {
|
||||
axios.mockResolvedValue({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate, unmount } = setup()
|
||||
const { waitForNextUpdate, unmount } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
unmount()
|
||||
|
||||
await setup().waitForNextUpdate()
|
||||
await setup('').waitForNextUpdate()
|
||||
|
||||
expect(axios).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
@ -114,7 +114,7 @@ describe('makeUseAxios', () => {
|
||||
makeUseAxios({ defaultOptions: { manual: true } })
|
||||
)
|
||||
|
||||
setup()
|
||||
setup('')
|
||||
|
||||
expect(axios).not.toHaveBeenCalled()
|
||||
})
|
||||
@ -128,13 +128,13 @@ describe('makeUseAxios', () => {
|
||||
|
||||
axios.mockResolvedValue({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate, unmount } = setup()
|
||||
const { waitForNextUpdate, unmount } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
unmount()
|
||||
|
||||
await setup().waitForNextUpdate()
|
||||
await setup('').waitForNextUpdate()
|
||||
|
||||
expect(axios).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
@ -175,7 +175,7 @@ describe('makeUseAxios', () => {
|
||||
})
|
||||
|
||||
function makeSetup(useAxios) {
|
||||
return (config = '', options = null) =>
|
||||
return (config, options = undefined) =>
|
||||
renderHook(
|
||||
({ config, options }) => {
|
||||
return useAxios(config, options)
|
||||
@ -202,7 +202,7 @@ function standardTests(
|
||||
it('should set loading to true and error to null before the request resolves', async () => {
|
||||
axios.mockResolvedValueOnce({ data: 'whatever' })
|
||||
|
||||
const { result, waitForNextUpdate } = setup()
|
||||
const { result, waitForNextUpdate } = setup('')
|
||||
|
||||
expect(result.current[0].loading).toBe(true)
|
||||
expect(result.current[0].error).toBe(null)
|
||||
@ -213,7 +213,7 @@ function standardTests(
|
||||
it('should set loading to false when request resolves', async () => {
|
||||
axios.mockResolvedValueOnce({ data: 'whatever' })
|
||||
|
||||
const { result, waitForNextUpdate } = setup()
|
||||
const { result, waitForNextUpdate } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -227,7 +227,7 @@ function standardTests(
|
||||
|
||||
axios.mockResolvedValueOnce(response)
|
||||
|
||||
const { result, waitForNextUpdate } = setup()
|
||||
const { result, waitForNextUpdate } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -241,7 +241,7 @@ function standardTests(
|
||||
|
||||
axios.mockRejectedValueOnce(error)
|
||||
|
||||
const { result, waitForNextUpdate } = setup()
|
||||
const { result, waitForNextUpdate } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -253,7 +253,7 @@ function standardTests(
|
||||
|
||||
axios.mockRejectedValueOnce(error)
|
||||
|
||||
const { result, waitForNextUpdate, rerender } = setup()
|
||||
const { result, waitForNextUpdate, rerender } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -271,7 +271,7 @@ function standardTests(
|
||||
|
||||
axios.mockRejectedValueOnce(error)
|
||||
|
||||
const firstRender = setup()
|
||||
const firstRender = setup('')
|
||||
|
||||
await firstRender.waitForNextUpdate()
|
||||
|
||||
@ -279,7 +279,7 @@ function standardTests(
|
||||
|
||||
axios.mockResolvedValueOnce({ data: 'whatever' })
|
||||
|
||||
const secondRender = setup()
|
||||
const secondRender = setup('')
|
||||
|
||||
await secondRender.waitForNextUpdate()
|
||||
|
||||
@ -291,7 +291,7 @@ function standardTests(
|
||||
|
||||
axios.mockRejectedValueOnce(error)
|
||||
|
||||
const { result, waitForNextUpdate } = setup()
|
||||
const { result, waitForNextUpdate } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -314,7 +314,7 @@ function standardTests(
|
||||
|
||||
axios.mockRejectedValueOnce(error)
|
||||
|
||||
const { result, waitForNextUpdate } = setup()
|
||||
const { result, waitForNextUpdate } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -325,7 +325,7 @@ function standardTests(
|
||||
it('should refetch', async () => {
|
||||
axios.mockResolvedValue({ data: 'whatever' })
|
||||
|
||||
const { result, waitForNextUpdate } = setup()
|
||||
const { result, waitForNextUpdate } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -342,7 +342,7 @@ function standardTests(
|
||||
it('should return the same reference to the fetch function', async () => {
|
||||
axios.mockResolvedValue({ data: 'whatever' })
|
||||
|
||||
const { result, rerender, waitForNextUpdate } = setup()
|
||||
const { result, rerender, waitForNextUpdate } = setup('')
|
||||
|
||||
const firstRefetch = result.current[1]
|
||||
|
||||
@ -358,9 +358,9 @@ function standardTests(
|
||||
|
||||
axios.mockResolvedValueOnce(response)
|
||||
|
||||
await setup().waitForNextUpdate()
|
||||
await setup('').waitForNextUpdate()
|
||||
|
||||
const { result } = setup()
|
||||
const { result } = setup('')
|
||||
|
||||
expect(result.current[0]).toEqual({
|
||||
loading: false,
|
||||
@ -376,7 +376,7 @@ function standardTests(
|
||||
it('should provide the cancel token to axios', async () => {
|
||||
axios.mockResolvedValueOnce({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate } = setup()
|
||||
const { waitForNextUpdate } = setup('')
|
||||
|
||||
expect(axios).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
@ -390,7 +390,7 @@ function standardTests(
|
||||
it('should cancel the outstanding request when the component unmounts', async () => {
|
||||
axios.mockResolvedValueOnce({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate, unmount } = setup()
|
||||
const { waitForNextUpdate, unmount } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -402,7 +402,7 @@ function standardTests(
|
||||
it('should cancel the outstanding request when the cancel method is called', async () => {
|
||||
axios.mockResolvedValue({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate, result } = setup()
|
||||
const { waitForNextUpdate, result } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -426,7 +426,7 @@ function standardTests(
|
||||
await waitForNextUpdate()
|
||||
})
|
||||
|
||||
it('should not cancel the outstanding request when the component rerenders with same config', async () => {
|
||||
it('should not cancel the outstanding request when the component rerenders with same string config', async () => {
|
||||
axios.mockResolvedValue({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate, rerender } = setup('initial config')
|
||||
@ -438,6 +438,42 @@ function standardTests(
|
||||
expect(cancel).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not cancel the outstanding request when the component rerenders with same object config', async () => {
|
||||
axios.mockResolvedValue({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate, rerender } = setup({ some: 'config' })
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
rerender()
|
||||
|
||||
expect(cancel).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not cancel the outstanding request when the component rerenders with equal string config', async () => {
|
||||
axios.mockResolvedValue({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate, rerender } = setup('initial config', {})
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
rerender({ config: 'initial config', options: {} })
|
||||
|
||||
expect(cancel).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not cancel the outstanding request when the component rerenders with equal object config', async () => {
|
||||
axios.mockResolvedValue({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate, rerender } = setup({ some: 'config' }, {})
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
rerender({ config: { some: 'config' }, options: {} })
|
||||
|
||||
expect(cancel).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should cancel the outstanding request when the cancel method is called after the component rerenders with same config', async () => {
|
||||
axios.mockResolvedValue({ data: 'whatever' })
|
||||
|
||||
@ -461,7 +497,7 @@ function standardTests(
|
||||
.fn()
|
||||
.mockImplementationOnce(err => err === cancellation)
|
||||
|
||||
const { result, waitFor } = setup()
|
||||
const { result, waitFor } = setup('')
|
||||
|
||||
// if we cancel we won't dispatch the error, hence there's no state update
|
||||
// to wait for. yet, if we don't try to wait, we won't know if we're handling
|
||||
@ -553,7 +589,7 @@ function standardTests(
|
||||
it('should cancel the outstanding manual refetch when the component refetches', async () => {
|
||||
axios.mockResolvedValue({ data: 'whatever' })
|
||||
|
||||
const { result, waitForNextUpdate, rerender } = setup()
|
||||
const { result, waitForNextUpdate, rerender } = setup('')
|
||||
|
||||
act(() => {
|
||||
result.current[1]()
|
||||
@ -624,7 +660,7 @@ function standardTests(
|
||||
axios.mockResolvedValueOnce(response)
|
||||
|
||||
// first component renders and stores results in cache
|
||||
await setup().waitForNextUpdate()
|
||||
await setup('').waitForNextUpdate()
|
||||
|
||||
const { result } = setup('', { manual: true })
|
||||
|
||||
@ -658,7 +694,7 @@ function standardTests(
|
||||
current: [, refetch]
|
||||
},
|
||||
waitForNextUpdate
|
||||
} = setup()
|
||||
} = setup('')
|
||||
|
||||
act(() => {
|
||||
expect(refetch()).resolves.toEqual(response)
|
||||
@ -679,7 +715,7 @@ function standardTests(
|
||||
current: [, refetch]
|
||||
},
|
||||
waitForNextUpdate
|
||||
} = setup()
|
||||
} = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -702,7 +738,7 @@ function standardTests(
|
||||
current: [, refetch]
|
||||
},
|
||||
waitForNextUpdate
|
||||
} = setup()
|
||||
} = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -723,7 +759,7 @@ function standardTests(
|
||||
current: [, refetch]
|
||||
},
|
||||
waitForNextUpdate
|
||||
} = setup()
|
||||
} = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -898,7 +934,7 @@ function standardTests(
|
||||
it('should not return response even if there is a cached one', async () => {
|
||||
axios.mockResolvedValueOnce({ data: 'whatever' })
|
||||
|
||||
await setup().waitForNextUpdate()
|
||||
await setup('').waitForNextUpdate()
|
||||
|
||||
const { result } = setup('', { manual: true })
|
||||
|
||||
@ -910,7 +946,7 @@ function standardTests(
|
||||
it('should use local state across rerenders', async () => {
|
||||
axios.mockResolvedValueOnce({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate, rerender } = setup()
|
||||
const { waitForNextUpdate, rerender } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -922,13 +958,13 @@ function standardTests(
|
||||
it('should not hit network across component mounts by default', async () => {
|
||||
axios.mockResolvedValueOnce({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate, unmount } = setup()
|
||||
const { waitForNextUpdate, unmount } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
unmount()
|
||||
|
||||
setup()
|
||||
setup('')
|
||||
|
||||
expect(axios).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
@ -968,7 +1004,7 @@ function standardTests(
|
||||
|
||||
unmount()
|
||||
|
||||
setup()
|
||||
setup('')
|
||||
|
||||
expect(axios).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
@ -1044,7 +1080,7 @@ function standardTests(
|
||||
|
||||
configure({ axios: mockAxios })
|
||||
|
||||
const { waitForNextUpdate } = setup()
|
||||
const { waitForNextUpdate } = setup('')
|
||||
|
||||
expect(mockAxios).toHaveBeenCalled()
|
||||
|
||||
@ -1057,7 +1093,7 @@ function standardTests(
|
||||
|
||||
axios.mockResolvedValueOnce({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate, rerender } = setup()
|
||||
const { waitForNextUpdate, rerender } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
@ -1071,13 +1107,13 @@ function standardTests(
|
||||
|
||||
axios.mockResolvedValue({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate, unmount } = setup()
|
||||
const { waitForNextUpdate, unmount } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
unmount()
|
||||
|
||||
await setup().waitForNextUpdate()
|
||||
await setup('').waitForNextUpdate()
|
||||
|
||||
expect(axios).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
@ -1088,7 +1124,7 @@ function standardTests(
|
||||
it('should override default manual option', () => {
|
||||
configure({ defaultOptions: { manual: true } })
|
||||
|
||||
setup()
|
||||
setup('')
|
||||
|
||||
expect(axios).not.toHaveBeenCalled()
|
||||
})
|
||||
@ -1100,13 +1136,13 @@ function standardTests(
|
||||
|
||||
axios.mockResolvedValue({ data: 'whatever' })
|
||||
|
||||
const { waitForNextUpdate, unmount } = setup()
|
||||
const { waitForNextUpdate, unmount } = setup('')
|
||||
|
||||
await waitForNextUpdate()
|
||||
|
||||
unmount()
|
||||
|
||||
await setup().waitForNextUpdate()
|
||||
await setup('').waitForNextUpdate()
|
||||
|
||||
expect(axios).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user