use-query-params
Advanced tools
Comparing version 0.4.1 to 0.4.2
@@ -16,2 +16,2 @@ import { EncodedQueryWithNulls, QueryParamConfig } from 'serialize-query-params'; | ||
*/ | ||
export declare const useQueryParam: <D, D2 = D>(name: string, paramConfig?: QueryParamConfig<D, D2>, rawQuery?: EncodedQueryWithNulls | undefined) => [D2 | undefined, (newValue: D, updateType?: "replace" | "replaceIn" | "push" | "pushIn" | undefined) => void]; | ||
export declare const useQueryParam: <D, D2 = D>(name: string, paramConfig?: QueryParamConfig<D, D2>, rawQuery?: EncodedQueryWithNulls | undefined) => [D2 | undefined, (newValue: D, updateType?: "replace" | "push" | "replaceIn" | "pushIn" | undefined) => void]; |
@@ -20,11 +20,25 @@ import * as React from 'react'; | ||
export var useQueryParam = function (name, paramConfig, rawQuery) { | ||
var _a; | ||
if (paramConfig === void 0) { paramConfig = StringParam; } | ||
var _a = React.useContext(QueryParamContext), history = _a.history, location = _a.location; | ||
var _b = React.useContext(QueryParamContext), history = _b.history, location = _b.location; | ||
// ref with current version history object (see #46) | ||
var refHistory = React.useRef(history); | ||
React.useEffect(function () { | ||
refHistory.current = history; | ||
}, [history]); | ||
// ref with current version location object (see #46) | ||
var refLocation = React.useRef(location); | ||
React.useEffect(function () { | ||
refLocation.current = location; | ||
}, [location]); | ||
// read in the raw query | ||
if (!rawQuery) { | ||
var locationIsObject_1 = typeof location === 'object'; | ||
var windowIsDefined_1 = typeof window !== 'undefined'; | ||
rawQuery = React.useMemo(function () { | ||
var pathname = {}; | ||
// handle checking SSR (#13) | ||
if (typeof location === 'object') { | ||
if (locationIsObject_1) { | ||
// in browser | ||
if (typeof window !== 'undefined') { | ||
if (windowIsDefined_1) { | ||
pathname = parseQueryString(location.search); | ||
@@ -38,6 +52,14 @@ } | ||
return pathname || {}; | ||
}, [location.search, location.pathname]); | ||
}, [location.search, location.pathname, locationIsObject_1, windowIsDefined_1]); | ||
} | ||
// read in the encoded string value | ||
var encodedValue = rawQuery[name]; | ||
// note that we use the stringified encoded value since the encoded | ||
// value may be an array that is recreated if a different query param | ||
// changes. It is sufficient to use this instead of encodedValue in | ||
// the useMemo dependency array since it will change any time the actual | ||
// meaningful value of encodedValue changes. | ||
var arraySafeEncodedValue = encodedValue instanceof Array | ||
? stringify((_a = {}, _a[name] = encodedValue, _a)) | ||
: encodedValue; | ||
// decode if the encoded value has changed, otherwise | ||
@@ -50,10 +72,3 @@ // re-use memoized value | ||
return paramConfig.decode(encodedValue); | ||
// note that we use the stringified encoded value since the encoded | ||
// value may be an array that is recreated if a different query param | ||
// changes. | ||
}, [ | ||
encodedValue instanceof Array | ||
? stringify({ name: encodedValue }) | ||
: encodedValue, | ||
]); | ||
}, [arraySafeEncodedValue, paramConfig]); // eslint-disable-line react-hooks/exhaustive-deps | ||
// create the setter, memoizing via useCallback | ||
@@ -63,5 +78,6 @@ var setValue = React.useCallback(function (newValue, updateType) { | ||
var newEncodedValue = paramConfig.encode(newValue); | ||
updateUrlQuery((_a = {}, _a[name] = newEncodedValue, _a), location, history, updateType); | ||
}, [location]); | ||
updateUrlQuery((_a = {}, _a[name] = newEncodedValue, _a), refLocation.current, // see #46 for why we use a ref here | ||
refHistory.current, updateType); | ||
}, [paramConfig, name]); | ||
return [decodedValue, setValue]; | ||
}; |
@@ -6,2 +6,20 @@ import * as React from 'react'; | ||
import { QueryParamContext } from './QueryParamProvider'; | ||
// from https://usehooks.com/usePrevious/ | ||
function usePrevious(value) { | ||
var ref = React.useRef(value); | ||
React.useEffect(function () { | ||
ref.current = value; | ||
}, [value]); | ||
return ref.current; | ||
} | ||
// from https://github.com/lodash/lodash/issues/2340#issuecomment-360325395 | ||
function isShallowEqual(objA, objB) { | ||
for (var key in objA) | ||
if (!(key in objB) || objA[key] !== objB[key]) | ||
return false; | ||
for (var key in objB) | ||
if (!(key in objA) || objA[key] !== objB[key]) | ||
return false; | ||
return true; | ||
} | ||
/** | ||
@@ -13,2 +31,21 @@ * Given a query parameter configuration (mapping query param name to { encode, decode }), | ||
var _a = React.useContext(QueryParamContext), history = _a.history, location = _a.location; | ||
// memoize paramConfigMap to make the API nicer for consumers. | ||
// otherwise we'd have to useQueryParams(useMemo(() => { foo: NumberParam }, [])) | ||
var prevParamConfigMap = usePrevious(paramConfigMap); | ||
var hasNewParamConfig = isShallowEqual(prevParamConfigMap, paramConfigMap); | ||
// prettier-ignore | ||
var memoParamConfigMap = React.useMemo(function () { return paramConfigMap; }, [ | ||
hasNewParamConfig, | ||
]); | ||
paramConfigMap = memoParamConfigMap; | ||
// ref with current version history object (see #46) | ||
var refHistory = React.useRef(history); | ||
React.useEffect(function () { | ||
refHistory.current = history; | ||
}, [history]); | ||
// ref with current version location object (see #46) | ||
var refLocation = React.useRef(location); | ||
React.useEffect(function () { | ||
refLocation.current = location; | ||
}, [location]); | ||
// read in the raw query | ||
@@ -31,3 +68,3 @@ var rawQuery = React.useMemo(function () { return parseQueryString(location.search) || {}; }, [location.search]); | ||
return decodedValues; | ||
}, paramValues); | ||
}, paramValues); // eslint-disable-line react-hooks/exhaustive-deps | ||
// create a setter for updating multiple query params at once | ||
@@ -38,4 +75,5 @@ var setQuery = React.useCallback(function (changes, updateType) { | ||
// update the URL | ||
updateUrlQuery(encodedChanges, location, history, updateType); | ||
}, [location]); | ||
updateUrlQuery(encodedChanges, refLocation.current, // see #46 | ||
refHistory.current, updateType); | ||
}, [paramConfigMap]); | ||
// no longer Partial | ||
@@ -42,0 +80,0 @@ return [decodedValues, setQuery]; |
@@ -16,2 +16,2 @@ import { EncodedQueryWithNulls, QueryParamConfig } from 'serialize-query-params'; | ||
*/ | ||
export declare const useQueryParam: <D, D2 = D>(name: string, paramConfig?: QueryParamConfig<D, D2>, rawQuery?: EncodedQueryWithNulls | undefined) => [D2 | undefined, (newValue: D, updateType?: "replace" | "replaceIn" | "push" | "pushIn" | undefined) => void]; | ||
export declare const useQueryParam: <D, D2 = D>(name: string, paramConfig?: QueryParamConfig<D, D2>, rawQuery?: EncodedQueryWithNulls | undefined) => [D2 | undefined, (newValue: D, updateType?: "replace" | "push" | "replaceIn" | "pushIn" | undefined) => void]; |
@@ -22,11 +22,25 @@ "use strict"; | ||
exports.useQueryParam = function (name, paramConfig, rawQuery) { | ||
var _a; | ||
if (paramConfig === void 0) { paramConfig = serialize_query_params_1.StringParam; } | ||
var _a = React.useContext(QueryParamProvider_1.QueryParamContext), history = _a.history, location = _a.location; | ||
var _b = React.useContext(QueryParamProvider_1.QueryParamContext), history = _b.history, location = _b.location; | ||
// ref with current version history object (see #46) | ||
var refHistory = React.useRef(history); | ||
React.useEffect(function () { | ||
refHistory.current = history; | ||
}, [history]); | ||
// ref with current version location object (see #46) | ||
var refLocation = React.useRef(location); | ||
React.useEffect(function () { | ||
refLocation.current = location; | ||
}, [location]); | ||
// read in the raw query | ||
if (!rawQuery) { | ||
var locationIsObject_1 = typeof location === 'object'; | ||
var windowIsDefined_1 = typeof window !== 'undefined'; | ||
rawQuery = React.useMemo(function () { | ||
var pathname = {}; | ||
// handle checking SSR (#13) | ||
if (typeof location === 'object') { | ||
if (locationIsObject_1) { | ||
// in browser | ||
if (typeof window !== 'undefined') { | ||
if (windowIsDefined_1) { | ||
pathname = serialize_query_params_1.parse(location.search); | ||
@@ -40,6 +54,14 @@ } | ||
return pathname || {}; | ||
}, [location.search, location.pathname]); | ||
}, [location.search, location.pathname, locationIsObject_1, windowIsDefined_1]); | ||
} | ||
// read in the encoded string value | ||
var encodedValue = rawQuery[name]; | ||
// note that we use the stringified encoded value since the encoded | ||
// value may be an array that is recreated if a different query param | ||
// changes. It is sufficient to use this instead of encodedValue in | ||
// the useMemo dependency array since it will change any time the actual | ||
// meaningful value of encodedValue changes. | ||
var arraySafeEncodedValue = encodedValue instanceof Array | ||
? serialize_query_params_1.stringify((_a = {}, _a[name] = encodedValue, _a)) | ||
: encodedValue; | ||
// decode if the encoded value has changed, otherwise | ||
@@ -52,10 +74,3 @@ // re-use memoized value | ||
return paramConfig.decode(encodedValue); | ||
// note that we use the stringified encoded value since the encoded | ||
// value may be an array that is recreated if a different query param | ||
// changes. | ||
}, [ | ||
encodedValue instanceof Array | ||
? serialize_query_params_1.stringify({ name: encodedValue }) | ||
: encodedValue, | ||
]); | ||
}, [arraySafeEncodedValue, paramConfig]); // eslint-disable-line react-hooks/exhaustive-deps | ||
// create the setter, memoizing via useCallback | ||
@@ -65,5 +80,6 @@ var setValue = React.useCallback(function (newValue, updateType) { | ||
var newEncodedValue = paramConfig.encode(newValue); | ||
updateUrlQuery_1.updateUrlQuery((_a = {}, _a[name] = newEncodedValue, _a), location, history, updateType); | ||
}, [location]); | ||
updateUrlQuery_1.updateUrlQuery((_a = {}, _a[name] = newEncodedValue, _a), refLocation.current, // see #46 for why we use a ref here | ||
refHistory.current, updateType); | ||
}, [paramConfig, name]); | ||
return [decodedValue, setValue]; | ||
}; |
@@ -8,2 +8,20 @@ "use strict"; | ||
var QueryParamProvider_1 = require("./QueryParamProvider"); | ||
// from https://usehooks.com/usePrevious/ | ||
function usePrevious(value) { | ||
var ref = React.useRef(value); | ||
React.useEffect(function () { | ||
ref.current = value; | ||
}, [value]); | ||
return ref.current; | ||
} | ||
// from https://github.com/lodash/lodash/issues/2340#issuecomment-360325395 | ||
function isShallowEqual(objA, objB) { | ||
for (var key in objA) | ||
if (!(key in objB) || objA[key] !== objB[key]) | ||
return false; | ||
for (var key in objB) | ||
if (!(key in objA) || objA[key] !== objB[key]) | ||
return false; | ||
return true; | ||
} | ||
/** | ||
@@ -15,2 +33,21 @@ * Given a query parameter configuration (mapping query param name to { encode, decode }), | ||
var _a = React.useContext(QueryParamProvider_1.QueryParamContext), history = _a.history, location = _a.location; | ||
// memoize paramConfigMap to make the API nicer for consumers. | ||
// otherwise we'd have to useQueryParams(useMemo(() => { foo: NumberParam }, [])) | ||
var prevParamConfigMap = usePrevious(paramConfigMap); | ||
var hasNewParamConfig = isShallowEqual(prevParamConfigMap, paramConfigMap); | ||
// prettier-ignore | ||
var memoParamConfigMap = React.useMemo(function () { return paramConfigMap; }, [ | ||
hasNewParamConfig, | ||
]); | ||
paramConfigMap = memoParamConfigMap; | ||
// ref with current version history object (see #46) | ||
var refHistory = React.useRef(history); | ||
React.useEffect(function () { | ||
refHistory.current = history; | ||
}, [history]); | ||
// ref with current version location object (see #46) | ||
var refLocation = React.useRef(location); | ||
React.useEffect(function () { | ||
refLocation.current = location; | ||
}, [location]); | ||
// read in the raw query | ||
@@ -33,3 +70,3 @@ var rawQuery = React.useMemo(function () { return serialize_query_params_1.parse(location.search) || {}; }, [location.search]); | ||
return decodedValues; | ||
}, paramValues); | ||
}, paramValues); // eslint-disable-line react-hooks/exhaustive-deps | ||
// create a setter for updating multiple query params at once | ||
@@ -40,4 +77,5 @@ var setQuery = React.useCallback(function (changes, updateType) { | ||
// update the URL | ||
updateUrlQuery_1.default(encodedChanges, location, history, updateType); | ||
}, [location]); | ||
updateUrlQuery_1.default(encodedChanges, refLocation.current, // see #46 | ||
refHistory.current, updateType); | ||
}, [paramConfigMap]); | ||
// no longer Partial | ||
@@ -44,0 +82,0 @@ return [decodedValues, setQuery]; |
{ | ||
"name": "use-query-params", | ||
"version": "0.4.1", | ||
"version": "0.4.2", | ||
"description": "React Hook for managing state in URL query parameters with easy serialization.", | ||
@@ -58,2 +58,3 @@ "main": "lib/index.js", | ||
"eslint-plugin-react": "^7.14.3", | ||
"eslint-plugin-react-hooks": "^2.1.2", | ||
"husky": "^3.0.5", | ||
@@ -60,0 +61,0 @@ "jest": "^24.5.0", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
85203
1705
24