Last active
April 1, 2021 22:32
-
-
Save osbornm/b356b9034f974825bc553b3105091092 to your computer and use it in GitHub Desktop.
React: useQueryStringState
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
useHistory, | |
useLocation | |
} from 'react-router-dom'; | |
import queryString from 'query-string'; | |
import { renderHook } from '@testing-library/react-hooks'; | |
import useQueryStringState from './useQueryStringState'; | |
const mockHistory = { push: jest.fn() }; | |
let mockLocation = { | |
search: 'foo=1', | |
pathname: 'path' | |
}; | |
jest.mock('query-string'); | |
jest.mock('react-router-dom', () => ({ | |
useHistory: () => {return mockHistory}, | |
useLocation: () => {return mockLocation} | |
})); | |
describe('useQueryStringState', () => { | |
beforeEach(() => { | |
jest.resetAllMocks(); | |
jest.clearAllMocks(); | |
}); | |
it('Calls query-string help with correct values and options', () => { | |
renderHook(() => useQueryStringState()); | |
expect(queryString.parse).toHaveBeenCalledWith('foo=1', { parseBooleans: true, parseNumbers: true, arrayFormat: 'comma' }); | |
}); | |
it('returns the parsed query plus the defaults', () => { | |
(queryString.parse as jest.Mock).mockReturnValue({ foo: 1 }); | |
const { result: { current } } = renderHook(() => useQueryStringState({ baz: 'buz', foo: 2 })); | |
expect(current[0]).toEqual({ | |
foo: 1, | |
baz: 'buz' | |
}); | |
}); | |
it('returns a set function that stringifies and calls push', () => { | |
(queryString.stringify as jest.Mock).mockReturnValue('stringifiedValue'); | |
const { result: { current } } = renderHook(() => useQueryStringState({ baz: 'buz', foo: 2 })); | |
const setState = current[1]; | |
setState({ value: 'foo', array: [1, 2, 3] }); | |
expect(queryString.stringify).toHaveBeenCalledWith({ value: 'foo', array: [1, 2, 3] }, { arrayFormat: 'comma' }); | |
expect(mockHistory.push).toHaveBeenCalledWith({ pathname: 'path', search: 'stringifiedValue' }); | |
}); | |
it('removes defaults when writing queryString', () => { | |
const { result: { current } } = renderHook(() => useQueryStringState({defaultToRemove: true})); | |
const setState = current[1]; | |
setState({ value: 'foo', defaultToRemove: true}); | |
expect(queryString.stringify).toHaveBeenCalledWith({ value: 'foo'}, { arrayFormat: 'comma' }); | |
}) | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
useHistory, | |
useLocation | |
} from "react-router-dom"; | |
import queryString from 'query-string'; | |
import { useMemo } from 'react'; | |
export default function useQueryStringState(defaults = {}): [any | undefined, (any) => void] { | |
const history = useHistory(); | |
const location = useLocation(); | |
const queryStringState = useMemo(() => { | |
const parsedQuery = queryString.parse(location.search, { parseBooleans: true, parseNumbers: true, arrayFormat: 'comma' }); | |
return { | |
...defaults, | |
...parsedQuery | |
}; | |
}, [location.search, defaults]); | |
const updateQueryStringState = (newState) => { | |
Object.keys(newState).forEach(k => { | |
if(newState[k] === defaults[k]) { | |
delete newState[k]; | |
} | |
}) | |
const qs = queryString.stringify(newState, { arrayFormat: 'comma' }); | |
history.push({ | |
pathname: location.pathname, | |
search: qs | |
}); | |
}; | |
return [queryStringState, updateQueryStringState]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment