Skip to content

Commit 848ba10

Browse files
fix: query params hook (#85)
* fix: effect cleanup debounce like * fix: rebased * fix: tests and add possibility to replace * feat: split methods
1 parent 2bb4742 commit 848ba10

File tree

4 files changed

+218
-45
lines changed

4 files changed

+218
-45
lines changed

packages/use-query-params/package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"reactjs",
99
"hooks",
1010
"params",
11+
"react-router-dom",
1112
"query-params"
1213
],
1314
"main": "dist/index.js",
@@ -26,11 +27,13 @@
2627
},
2728
"license": "MIT",
2829
"dependencies": {
29-
"query-string": "^6.14.1"
30+
"query-string": "^6.14.1",
31+
"react-router-dom": "^5.2.0"
3032
},
3133
"peerDependencies": {
3234
"react": "17.x",
33-
"react-dom": "17.x"
35+
"react-dom": "17.x",
36+
"react-router-dom": "^5.2.0"
3437
},
3538
"devDependencies": {
3639
"@testing-library/jest-dom": "^5.11.9",

packages/use-query-params/src/__tests__/index.js

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
import { act, renderHook } from '@testing-library/react-hooks'
2+
import React from 'react'
3+
import { MemoryRouter } from 'react-router-dom'
24
import useQueryParam from '../index'
35

46
// eslint-disable-next-line react/prop-types
5-
const wrapper = ({ pathname = 'one', search }) => ({ children }) => {
6-
window.history.replaceState(
7-
window.history.state,
8-
null,
9-
`${pathname}?${search}`,
10-
)
11-
12-
return children
13-
}
7+
const wrapper = ({ pathname = 'one', search }) => ({ children }) => (
8+
<MemoryRouter initialIndex={0} initialEntries={[{ pathname, search }]}>
9+
{children}
10+
</MemoryRouter>
11+
)
1412

1513
describe('useQueryParam', () => {
1614
it('should set one object', () => {
@@ -117,7 +115,7 @@ describe('useQueryParam', () => {
117115
})
118116
})
119117

120-
it('should correctly set different objects before rerender', async () => {
118+
it('should correctly set different objects before rerender', () => {
121119
const { result, rerender } = renderHook(() => useQueryParam(), {
122120
wrapper: wrapper({ search: '' }),
123121
})
@@ -150,4 +148,62 @@ describe('useQueryParam', () => {
150148
test: 'Scaleway',
151149
})
152150
})
151+
152+
test('should render good params with parallel changes', async () => {
153+
jest.useFakeTimers()
154+
const { result } = renderHook(() => useQueryParam(), {
155+
wrapper: wrapper({ search: '' }),
156+
})
157+
act(() => {
158+
result.current.setQueryParams({ name: 'John' })
159+
result.current.setQueryParams({ lastName: 'Doe' })
160+
result.current.setQueryParams({ compagny: 'Scaleway' })
161+
})
162+
163+
jest.runAllTimers()
164+
165+
expect(result.current.queryParams).toEqual({
166+
name: 'John',
167+
lastName: 'Doe',
168+
compagny: 'Scaleway',
169+
})
170+
171+
act(() => {
172+
result.current.setQueryParams({ name: 'John' })
173+
})
174+
175+
jest.runAllTimers()
176+
177+
expect(result.current.queryParams).toEqual({
178+
name: 'John',
179+
lastName: 'Doe',
180+
compagny: 'Scaleway',
181+
})
182+
})
183+
184+
test('should erase params', () => {
185+
const { result } = renderHook(() => useQueryParam(), {
186+
wrapper: wrapper({ search: '' }),
187+
})
188+
189+
act(() => {
190+
result.current.setQueryParams({ name: 'John' })
191+
})
192+
expect(result.current.queryParams).toEqual({
193+
name: 'John',
194+
})
195+
act(() => {
196+
result.current.setQueryParams({ lastName: 'Doe' })
197+
})
198+
expect(result.current.queryParams).toEqual({
199+
name: 'John',
200+
lastName: 'Doe',
201+
})
202+
act(() => {
203+
result.current.replaceQueryparams({ compagny: 'Scaleway' })
204+
})
205+
expect(result.current.queryParams).toEqual({
206+
compagny: 'Scaleway',
207+
})
208+
})
153209
})

packages/use-query-params/src/index.js

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,65 @@
11
import { parse, stringify } from 'query-string'
22
import { useCallback, useEffect, useState } from 'react'
3+
import { useHistory } from 'react-router-dom'
34

4-
const parseFormat = search =>
5-
parse(search, {
6-
parseNumbers: true,
7-
parseBooleans: true,
8-
arrayFormat: 'comma',
9-
})
5+
const useQueryParams = () => {
6+
const {
7+
location: { search, pathname },
8+
replace,
9+
} = useHistory()
1010

11-
const stringyFormat = params =>
12-
stringify(params, {
13-
arrayFormat: 'comma',
14-
sort: (a, b) => a.localeCompare(b),
15-
})
11+
const parseFormat = useCallback(
12+
() =>
13+
parse(search, {
14+
parseNumbers: true,
15+
parseBooleans: true,
16+
arrayFormat: 'comma',
17+
}),
18+
[search],
19+
)
1620

17-
const useQueryParams = () => {
18-
const { search, pathname } = window.location
21+
const stringyFormat = useCallback(
22+
params =>
23+
stringify(params, {
24+
arrayFormat: 'comma',
25+
sort: (a, b) => a.localeCompare(b),
26+
}),
27+
[],
28+
)
1929

20-
const [state, setState] = useState(parseFormat(search))
30+
const [state, setState] = useState(parseFormat())
2131

22-
const setQueryParams = useCallback(nextParams => {
32+
/**
33+
* Set query params in the url. It merge the existing values with the new ones.
34+
* @param {Object} nextParams The params to set in the url as query params
35+
*/
36+
const setQueryParams = nextParams => {
2337
setState(prevState => ({ ...prevState, ...nextParams }))
24-
}, [])
38+
}
39+
40+
/**
41+
* Replace the query params in the url. It erase all current values and put the new ones
42+
* @param {Object} newParams
43+
*/
44+
const replaceQueryparams = newParams => {
45+
setState({ ...newParams })
46+
}
2547

2648
useEffect(() => {
27-
const stringifiedParams = stringyFormat(state)
28-
window.history.replaceState(
29-
window.history.state,
30-
null,
31-
`${pathname}?${stringifiedParams}`,
32-
)
33-
}, [pathname, state])
49+
const handler = setTimeout(() => {
50+
const stringifiedParams = stringyFormat(state)
51+
if (search !== `?${stringifiedParams}`)
52+
replace(`${pathname}?${stringifiedParams}`)
53+
}, 500)
54+
55+
return () => {
56+
clearTimeout(handler)
57+
}
58+
}, [pathname, replace, state, search, stringyFormat])
3459

3560
return {
3661
queryParams: state,
62+
replaceQueryparams,
3763
setQueryParams,
3864
}
3965
}

0 commit comments

Comments
 (0)