Skip to content

Commit

Permalink
feat(use-query-params): add ability to push instead of replacing curr…
Browse files Browse the repository at this point in the history
…ent history (#355)

* feat(use-query-params): add ability to push instead of replacing current history

* docs: update readme

* fix: use correct history version

* Update packages/use-query-params/README.md

Co-authored-by: Adrien Gibrat <adrien.gibrat@gmail.com>

Co-authored-by: Adrien Gibrat <adrien.gibrat@gmail.com>
  • Loading branch information
chambo-e and adriengibrat authored Sep 1, 2021
1 parent 95fa09b commit 2628127
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 32 deletions.
25 changes: 25 additions & 0 deletions packages/use-query-params/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,28 @@ const Component = () => {
)
}
```

### Push onto the stack instead of replacing

To avoid mutating history

```js
// In this exemple we assume that we have an URL that include : `?company=Scaleway".
import React from 'react'
import useQueryParams from '@scaleway/use-query-params'

const Component = () => {
const { queryParams, replaceQueryParams } = useQueryParams()
const { user, company } = queryParams // user will be undefined and company will be "Scaleway"
const setUser = () => replaceQueryParams({ user: 'John' }, { push: true }) // user will be "John" and company will be undefined
// ?user=John

return (
<>
<h1>User: {user}</h1>
<h1>Company: {company}</h1>
<button onClick={setUser}>Set User John</button>
</>
)
}
```
2 changes: 1 addition & 1 deletion packages/use-query-params/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
},
"license": "MIT",
"dependencies": {
"history": "^5.0.0",
"history": "^4.9.0",
"query-string": "^7.0.0",
"react-router-dom": "^5.2.0"
},
Expand Down
44 changes: 39 additions & 5 deletions packages/use-query-params/src/__tests__/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,53 @@
import { act, renderHook } from '@testing-library/react-hooks'
import { History, createMemoryHistory } from 'history'
import React, { ReactNode } from 'react'
import { MemoryRouter } from 'react-router-dom'
import { MemoryRouter, Router } from 'react-router-dom'
import useQueryParams from '..'

const wrapper =
({ pathname = 'one', search }: { pathname?: string, search: string }) =>
({ pathname = 'one', search, history }: { pathname?: string, search: string, history?: History }) =>
// eslint-disable-next-line react/prop-types
({ children }: { children: ReactNode }) =>
(
<MemoryRouter initialIndex={0} initialEntries={[{ pathname, search }]}>
{children}
</MemoryRouter>
history ? (
<Router history={history}>
{children}
</Router>
) : (
<MemoryRouter initialIndex={0} initialEntries={[{ pathname, search }]}>
{children}
</MemoryRouter>
)
)

describe('useQueryParam', () => {
it('should correctly push instead of replacing history', () => {
const history = createMemoryHistory({
initialEntries: ['user=john'],
initialIndex: 0,
})

const { result } = renderHook(() => useQueryParams(), {
wrapper: wrapper({ history, search: '' }),
})

act(() => {
result.current.setQueryParams({ user: 'John' })
})
expect(result.current.queryParams).toEqual({ user: 'John' })
expect(history.length).toBe(1)
act(() => {
result.current.setQueryParams({ user: 'Jack' })
})
expect(result.current.queryParams).toEqual({ user: 'Jack' })
expect(history.length).toBe(1)
act(() => {
result.current.setQueryParams({ user: 'Jerry' }, { push: true })
})
expect(result.current.queryParams).toEqual({ user: 'Jerry' })
expect(history.length).toBe(2)
})

it('should set one object', () => {
const { result } = renderHook(() => useQueryParams(), {
wrapper: wrapper({ search: 'user=john' }),
Expand Down
46 changes: 28 additions & 18 deletions packages/use-query-params/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,30 @@ import { ParsedQuery, parse, stringify } from 'query-string'
import { useCallback, useMemo } from 'react'
import { useHistory, useLocation } from 'react-router-dom'

interface Options {
/** Set to true to push a new entry onto the history stack */
push: boolean
}

const useQueryParams = (): {
queryParams: ParsedQuery<string | number | boolean>;
replaceQueryParams: (newParams: Record<string, unknown>) => void;
setQueryParams: (nextParams: Record<string, unknown>) => void;
/**
* Replace the query params in the url. It erase all current values and put the new ones
*
* @param newParams - The values to set in the query string, overweriting existing one
* @param options - Options to define behavior
*/
replaceQueryParams: typeof replaceQueryParams
/**
* Set query params in the url. It merge the existing values with the new ones.
*
* @param nextParams - The values to add or update in the existing query string
* @param options - Options to define behavior
*/
setQueryParams: typeof setQueryParams
} => {
// eslint-disable-next-line @typescript-eslint/unbound-method
const { replace } = useHistory<History>()
const { replace, push } = useHistory<History>()
// eslint-disable-next-line @typescript-eslint/unbound-method
const location = useLocation<History>()

Expand All @@ -35,35 +52,28 @@ const useQueryParams = (): {
)

const replaceInUrlIfNeeded = useCallback(
newState => {
(newState: Record<string,unknown>, options?: Options) => {
const stringifiedParams = stringyFormat(newState)
const searchToCompare = location.search || '?'

if (searchToCompare !== `?${stringifiedParams}`) {
replace(`${location.pathname}?${stringifiedParams}`)
const fn = options?.push ? push : replace
fn(`${location.pathname}?${stringifiedParams}`)
}
},
[replace, location.pathname, location.search, stringyFormat],
[push, replace, location.pathname, location.search, stringyFormat],
)

/**
* Set query params in the url. It merge the existing values with the new ones.
* @param {Object} nextParams The params to set in the url as query params
*/
const setQueryParams = useCallback(
(nextParams: Record<string,unknown>): void => {
replaceInUrlIfNeeded({ ...currentState, ...nextParams })
(nextParams: Record<string,unknown>, options?: Options): void => {
replaceInUrlIfNeeded({ ...currentState, ...nextParams }, options)
},
[currentState, replaceInUrlIfNeeded],
)

/**
* Replace the query params in the url. It erase all current values and put the new ones
* @param {Object} newParams
*/
const replaceQueryParams = useCallback(
(newParams: Record<string,unknown>): void => {
replaceInUrlIfNeeded({ ...newParams })
(newParams: Record<string,unknown>, options?: Options): void => {
replaceInUrlIfNeeded(newParams, options)
},
[replaceInUrlIfNeeded],
)
Expand Down
9 changes: 1 addition & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,7 @@
core-js-pure "^3.0.0"
regenerator-runtime "^0.13.4"

"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
version "7.15.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b"
integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==
Expand Down Expand Up @@ -4732,13 +4732,6 @@ history@^4.9.0:
tiny-warning "^1.0.0"
value-equal "^1.0.1"

history@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/history/-/history-5.0.1.tgz#de35025ed08bce0db62364b47ebbf9d97b5eb06a"
integrity sha512-5qC/tFUKfVci5kzgRxZxN5Mf1CV8NmJx9ByaPX0YTLx5Vz3Svh7NYp6eA4CpDq4iA9D0C1t8BNIfvQIrUI3mVw==
dependencies:
"@babel/runtime" "^7.7.6"

hoist-non-react-statics@^3.1.0:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
Expand Down

0 comments on commit 2628127

Please sign in to comment.