From 5b092013b65fa44c3be6a8d5799bb7c54a3a4242 Mon Sep 17 00:00:00 2001 From: Emmanuel Chambon Date: Tue, 31 Aug 2021 17:28:47 +0200 Subject: [PATCH 1/4] feat(use-query-params): add ability to push instead of replacing current history --- .../use-query-params/src/__tests__/index.tsx | 46 +++++++++++++++++-- packages/use-query-params/src/index.ts | 46 +++++++++++-------- 2 files changed, 69 insertions(+), 23 deletions(-) diff --git a/packages/use-query-params/src/__tests__/index.tsx b/packages/use-query-params/src/__tests__/index.tsx index 8af706244..3f46f731d 100644 --- a/packages/use-query-params/src/__tests__/index.tsx +++ b/packages/use-query-params/src/__tests__/index.tsx @@ -1,19 +1,55 @@ 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 }) => ( - - {children} - + history ? ( + + {children} + + ) : ( + + {children} + + ) ) 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) + + console.log(history) + }) + it('should set one object', () => { const { result } = renderHook(() => useQueryParams(), { wrapper: wrapper({ search: 'user=john' }), diff --git a/packages/use-query-params/src/index.ts b/packages/use-query-params/src/index.ts index 8e1b616d5..9d963f66e 100644 --- a/packages/use-query-params/src/index.ts +++ b/packages/use-query-params/src/index.ts @@ -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; - replaceQueryParams: (newParams: Record) => void; - setQueryParams: (nextParams: Record) => 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() + const { replace, push } = useHistory() // eslint-disable-next-line @typescript-eslint/unbound-method const location = useLocation() @@ -35,35 +52,28 @@ const useQueryParams = (): { ) const replaceInUrlIfNeeded = useCallback( - newState => { + (newState: Record, 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): void => { - replaceInUrlIfNeeded({ ...currentState, ...nextParams }) + (nextParams: Record, 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): void => { - replaceInUrlIfNeeded({ ...newParams }) + (newParams: Record, options?: Options): void => { + replaceInUrlIfNeeded(newParams, options) }, [replaceInUrlIfNeeded], ) From c9e684ce6177f1b85fc38e03517549d4f4e7c173 Mon Sep 17 00:00:00 2001 From: Emmanuel Chambon Date: Tue, 31 Aug 2021 17:31:24 +0200 Subject: [PATCH 2/4] docs: update readme --- packages/use-query-params/README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/use-query-params/README.md b/packages/use-query-params/README.md index 070187f45..368d969d6 100644 --- a/packages/use-query-params/README.md +++ b/packages/use-query-params/README.md @@ -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, setQueryParams } = 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 ( + <> +

User: {user}

+

Company: {company}

+ + + ) +} +``` From 209d3565f06ee8013c8bbd57e4a25bb552061069 Mon Sep 17 00:00:00 2001 From: Emmanuel Chambon Date: Tue, 31 Aug 2021 17:54:42 +0200 Subject: [PATCH 3/4] fix: use correct history version --- packages/use-query-params/package.json | 2 +- packages/use-query-params/src/__tests__/index.tsx | 2 -- yarn.lock | 9 +-------- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/use-query-params/package.json b/packages/use-query-params/package.json index 534de51fc..517895b33 100644 --- a/packages/use-query-params/package.json +++ b/packages/use-query-params/package.json @@ -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" }, diff --git a/packages/use-query-params/src/__tests__/index.tsx b/packages/use-query-params/src/__tests__/index.tsx index 3f46f731d..8c6e87df3 100644 --- a/packages/use-query-params/src/__tests__/index.tsx +++ b/packages/use-query-params/src/__tests__/index.tsx @@ -46,8 +46,6 @@ describe('useQueryParam', () => { }) expect(result.current.queryParams).toEqual({ user: 'Jerry' }) expect(history.length).toBe(2) - - console.log(history) }) it('should set one object', () => { diff --git a/yarn.lock b/yarn.lock index 6f9a6faf0..622ce3341 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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== @@ -4794,13 +4794,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" From c38f35b7eccf69de5fe5f23138ffcb6ac19f4b59 Mon Sep 17 00:00:00 2001 From: Manu Chambon Date: Wed, 1 Sep 2021 15:27:10 +0200 Subject: [PATCH 4/4] Update packages/use-query-params/README.md Co-authored-by: Adrien Gibrat --- packages/use-query-params/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/use-query-params/README.md b/packages/use-query-params/README.md index 368d969d6..1548e3dfa 100644 --- a/packages/use-query-params/README.md +++ b/packages/use-query-params/README.md @@ -97,7 +97,7 @@ import React from 'react' import useQueryParams from '@scaleway/use-query-params' const Component = () => { - const { queryParams, setQueryParams } = useQueryParams() + 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