use-location-state
Advanced tools
Comparing version 2.3.1 to 2.4.0
@@ -11,14 +11,14 @@ 'use strict'; | ||
/*! ***************************************************************************** | ||
Copyright (c) Microsoft Corporation. All rights reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
this file except in compliance with the License. You may obtain a copy of the | ||
License at http://www.apache.org/licenses/LICENSE-2.0 | ||
Copyright (c) Microsoft Corporation. | ||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED | ||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
MERCHANTABLITY OR NON-INFRINGEMENT. | ||
Permission to use, copy, modify, and/or distribute this software for any | ||
purpose with or without fee is hereby granted. | ||
See the Apache Version 2.0 License for specific language governing permissions | ||
and limitations under the License. | ||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | ||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | ||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | ||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
PERFORMANCE OF THIS SOFTWARE. | ||
***************************************************************************** */ | ||
@@ -75,71 +75,54 @@ | ||
function useQueryStateObj(defaultQueryState, queryStateOpts) { | ||
var queryStringInterface = queryStateOpts.queryStringInterface; | ||
var hashQSI = useHashQueryStringInterface(queryStringInterface && { disabled: true }); | ||
var activeQSI = queryStringInterface || hashQSI; | ||
var queryString = activeQSI.getQueryString(); | ||
var _a = react.useState(), setLatestMergedQueryString = _a[1]; | ||
var queryState = react.useMemo(function () { return (__assign(__assign({}, defaultQueryState), queryStateCore.parseQueryState(queryString))); }, [defaultQueryState, queryString]); | ||
var ref = react.useRef({ | ||
defaultQueryState: defaultQueryState, | ||
queryStateOpts: queryStateOpts, | ||
activeQSI: activeQSI, | ||
}); | ||
var setQueryState = react.useCallback(function (newState, opts) { | ||
var _a = ref.current, defaultQueryState = _a.defaultQueryState, queryStateOpts = _a.queryStateOpts, activeQSI = _a.activeQSI; | ||
var _b = queryStateOpts.stripDefaults, stripDefaults = _b === void 0 ? true : _b; | ||
var stripOverwrite = {}; | ||
// when a params are set to the same value as in the defaults | ||
// we remove them to avoid having two URLs reproducing the same state unless stripDefaults === false | ||
if (stripDefaults) { | ||
Object.entries(newState).forEach(function (_a) { | ||
var key = _a[0]; | ||
if (defaultQueryState[key] === newState[key]) { | ||
stripOverwrite[key] = null; | ||
} | ||
}); | ||
} | ||
// retrieve the last value (by re-executing the search getter) | ||
var currentQueryState = __assign(__assign({}, defaultQueryState), queryStateCore.parseQueryState(activeQSI.getQueryString())); | ||
var mergedQueryString = queryStateCore.createMergedQuery(currentQueryState || {}, newState, stripOverwrite); | ||
activeQSI.setQueryString(mergedQueryString, opts || {}); | ||
// triggers an update (in case the QueryStringInterface misses to do so) | ||
setLatestMergedQueryString(mergedQueryString); | ||
}, []); | ||
react.useEffect(function () { | ||
ref.current = { | ||
defaultQueryState: defaultQueryState, | ||
queryStateOpts: queryStateOpts, | ||
activeQSI: activeQSI, | ||
}; | ||
}); | ||
return [queryState, setQueryState]; | ||
function useRefLatest(value) { | ||
var ref = react.useRef(value); | ||
react.useLayoutEffect(function () { | ||
ref.current = value; | ||
}, [value]); | ||
return ref; | ||
} | ||
function sameAsJsonString(compareValueA, compareValueB) { | ||
return JSON.stringify(compareValueA) === JSON.stringify(compareValueB); | ||
} | ||
function useQueryState(itemName, defaultValue, queryStateOpts) { | ||
if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
defaultValue = react.useState(defaultValue)[0]; | ||
var defaultQueryStateValue = queryStateCore.toQueryStateValue(defaultValue); | ||
var defaultQueryState = react.useMemo(function () { | ||
var _a; | ||
return defaultQueryStateValue | ||
? (_a = {}, | ||
_a[itemName] = defaultQueryStateValue, | ||
_a) : {}; | ||
}, [itemName, defaultQueryStateValue]); | ||
var queryStateOptsDefaults = Object.freeze({}); | ||
function useQueryReducer(itemName, reducer, initialStateOrInitialArg, initStateFnOrOpts, queryStateOpts) { | ||
var _a; | ||
var mergedQueryStateOpts = Object.assign({}, queryStateOptsDefaults, queryStateOpts, typeof initStateFnOrOpts === 'object' ? initStateFnOrOpts : null); | ||
var queryStringInterface = mergedQueryStateOpts.queryStringInterface; | ||
var hashQSI = useHashQueryStringInterface(queryStringInterface ? { disabled: true } : undefined); | ||
var activeQSI = queryStringInterface || hashQSI; | ||
// itemName & defaultValue is not allowed to be changed after init | ||
var defaultValue = react.useState(function () { | ||
return initStateFnOrOpts && typeof initStateFnOrOpts === 'function' | ||
? initStateFnOrOpts(initialStateOrInitialArg) | ||
: initialStateOrInitialArg; | ||
})[0]; | ||
var defaultQueryStateValue = react.useMemo(function () { return queryStateCore.toQueryStateValue(defaultValue); }, [defaultValue]); | ||
if (defaultQueryStateValue === null) { | ||
throw new Error('unsupported defaultValue'); | ||
} | ||
var _a = useQueryStateObj(defaultQueryState, queryStateOpts), queryState = _a[0], setQueryState = _a[1]; | ||
var setQueryStateItem = react.useCallback(function (newValue, opts) { | ||
var ref = useRefLatest({ | ||
activeQSI: activeQSI, | ||
defaultValue: defaultValue, | ||
mergedQueryStateOpts: mergedQueryStateOpts, | ||
reducer: reducer, | ||
}); | ||
var resetQueryStateItem = react.useCallback(function (opts) { | ||
var _a; | ||
// stringify the given value (or array of strings) | ||
var activeQSI = ref.current.activeQSI; | ||
var currentState = queryStateCore.parseQueryState(activeQSI.getQueryString()) || {}; | ||
var newState = __assign(__assign({}, currentState), (_a = {}, _a[itemName] = null, _a)); | ||
activeQSI.setQueryString(queryStateCore.createMergedQuery(newState), opts); | ||
setR(function (rC) { return rC + 1; }); | ||
}, [itemName, ref]); | ||
var _b = react.useState(0), setR = _b[1]; | ||
var dispatch = react.useCallback(function (action, opts) { | ||
var _a; | ||
if (opts === void 0) { opts = {}; } | ||
var _b = ref.current, activeQSI = _b.activeQSI, defaultValue = _b.defaultValue, mergedQueryStateOpts = _b.mergedQueryStateOpts, reducer = _b.reducer; | ||
var _c = mergedQueryStateOpts.stripDefaults, stripDefaults = _c === void 0 ? true : _c; | ||
var currentState = queryStateCore.parseQueryState(activeQSI.getQueryString()) || {}; | ||
var currentValue = itemName in currentState | ||
? queryStateCore.parseQueryStateValue(currentState[itemName], defaultValue) | ||
: defaultValue; | ||
var newValue = reducer(currentValue !== null && currentValue !== void 0 ? currentValue : defaultValue, action); | ||
var newQueryStateValue = queryStateCore.toQueryStateValue(newValue); | ||
// warn when value type is not supported (do not warn when null was passed explicitly) | ||
if ((newQueryStateValue === null && newValue !== newQueryStateValue) || | ||
!(newQueryStateValue !== null && | ||
typeof queryStateCore.parseQueryStateValue(newQueryStateValue, defaultValue) === typeof defaultValue)) { | ||
if (newQueryStateValue === null) { | ||
console.warn('value of ' + | ||
@@ -149,32 +132,40 @@ JSON.stringify(newValue) + | ||
itemName + | ||
'" will reset to default value', defaultValue); | ||
newQueryStateValue = null; | ||
'" will reset to default value of:', defaultValue); | ||
} | ||
// when new value is equal to default, we call setQueryState with a null value to reset query string | ||
// arrays have to be compared json stringified, other values can compared by value | ||
if (Array.isArray(defaultValue) && sameAsJsonString(newValue, defaultValue)) { | ||
newQueryStateValue = null; | ||
// when a params are set to the same value as in the defaults | ||
// we remove them to avoid having two URLs reproducing the same state unless stripDefaults === false | ||
if (stripDefaults) { | ||
if (Array.isArray(defaultValue) && sameAsJsonString(newValue, defaultValue)) { | ||
return resetQueryStateItem(opts); | ||
} | ||
else if (newValue === defaultValue) { | ||
return resetQueryStateItem(opts); | ||
} | ||
} | ||
else if (newValue === defaultValue) { | ||
newQueryStateValue = null; | ||
} | ||
setQueryState((_a = {}, _a[itemName] = newQueryStateValue, _a), opts); | ||
}, [defaultValue, itemName, setQueryState]); | ||
// fallback to default value | ||
var value = defaultValue; | ||
var queryStateItem = queryState[itemName]; | ||
var queryStateValue = null; | ||
if (queryStateItem || queryStateItem === '') { | ||
queryStateValue = queryStateCore.parseQueryStateValue(queryStateItem, defaultValue); | ||
} | ||
if (queryStateValue !== null && typeof queryStateValue === typeof defaultValue) { | ||
value = queryStateValue; | ||
} | ||
return [value, setQueryStateItem]; | ||
activeQSI.setQueryString(queryStateCore.createMergedQuery(__assign(__assign({}, currentState), (_a = {}, _a[itemName] = queryStateCore.toQueryStateValue(newValue), _a))), opts); | ||
// force re-render | ||
setR(function (rC) { return rC + 1; }); | ||
}, [itemName, ref, resetQueryStateItem]); | ||
var currentState = queryStateCore.parseQueryState(activeQSI.getQueryString()) || {}; | ||
var currentValue = (_a = (itemName in currentState | ||
? queryStateCore.parseQueryStateValue(currentState[itemName], defaultValue) | ||
: defaultValue)) !== null && _a !== void 0 ? _a : defaultValue; | ||
return [currentValue, dispatch]; | ||
} | ||
function sameAsJsonString(compareValueA, compareValueB) { | ||
return JSON.stringify(compareValueA) === JSON.stringify(compareValueB); | ||
} | ||
function useHashQueryState(itemName, defaultValue, queryStateOpts) { | ||
function useQueryState(itemName, initialState, queryStateOpts) { | ||
if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
var hashQSI = useHashQueryStringInterface(); | ||
return useQueryState(itemName, defaultValue, __assign(__assign({}, queryStateOpts), { queryStringInterface: hashQSI })); | ||
var reducer = react.useCallback(function (prevState, action) { | ||
if (action && typeof action === 'function') { | ||
return action(prevState); | ||
} | ||
return action; | ||
}, []); | ||
if (typeof initialState === 'function') { | ||
return useQueryReducer(itemName, reducer, undefined, initialState, queryStateOpts); | ||
} | ||
return useQueryReducer(itemName, reducer, initialState, queryStateOpts); | ||
} | ||
@@ -217,7 +208,7 @@ | ||
return; | ||
var hashChangeHandler = function () { | ||
var popstateHandler = function () { | ||
setR(function (r) { return r + 1; }); | ||
}; | ||
window.addEventListener('popstate', hashChangeHandler, false); | ||
return function () { return window.removeEventListener('popstate', hashChangeHandler, false); }; | ||
window.addEventListener('popstate', popstateHandler, false); | ||
return function () { return window.removeEventListener('popstate', popstateHandler, false); }; | ||
}, [enabled]); | ||
@@ -229,5 +220,12 @@ return locationStateInterface; | ||
var locationStateOptsDefaults = Object.freeze({}); | ||
function useLocationState(itemName, defaultValue, _a) { | ||
var locationStateInterface = (_a === void 0 ? locationStateOptsDefaults : _a).locationStateInterface; | ||
defaultValue = react.useState(defaultValue)[0]; | ||
function useLocationReducer(itemName, reducer, initialStateOrInitialArg, maybeInitStateFnOrOpts, opts) { | ||
var locationStateInterface = (opts || | ||
(typeof maybeInitStateFnOrOpts === 'object' && maybeInitStateFnOrOpts) || | ||
locationStateOptsDefaults).locationStateInterface; | ||
// itemName & defaultValue is not allowed to be changed after init | ||
var defaultValue = react.useState(function () { | ||
return maybeInitStateFnOrOpts && typeof maybeInitStateFnOrOpts === 'function' | ||
? maybeInitStateFnOrOpts(initialStateOrInitialArg) | ||
: initialStateOrInitialArg; | ||
})[0]; | ||
// throw for invalid values like functions | ||
@@ -238,3 +236,3 @@ if (!validTypes.includes(typeof defaultValue)) { | ||
itemName = react.useState(function () { | ||
var suffixObscurer = typeof btoa !== "undefined" ? btoa : (function (s) { return s; }); | ||
var suffixObscurer = typeof btoa !== 'undefined' ? btoa : function (s) { return s; }; | ||
var suffix = suffixObscurer(Array.isArray(defaultValue) ? 'array' : typeof defaultValue).replace(/=/g, ''); | ||
@@ -246,4 +244,5 @@ return itemName + "__" + suffix; | ||
var activeLSI = locationStateInterface || standardLSI; | ||
var ref = react.useRef({ | ||
var ref = useRefLatest({ | ||
activeLSI: activeLSI, | ||
reducer: reducer, | ||
}); | ||
@@ -263,17 +262,10 @@ var currentState = activeLSI.getLocationState(); | ||
activeLSI.setLocationState(newState, opts); | ||
}, [itemName]); | ||
var setLocationStateItem = react.useCallback(function (newValueOrFn, opts) { | ||
}, [itemName, ref]); | ||
var dispatchAction = react.useCallback(function (action, opts) { | ||
var _a; | ||
if (opts === void 0) { opts = {}; } | ||
var _b = ref.current.activeLSI, getLocationState = _b.getLocationState, setLocationState = _b.setLocationState; | ||
var newValue; | ||
var _b = ref.current, reducer = _b.reducer, _c = _b.activeLSI, getLocationState = _c.getLocationState, setLocationState = _c.setLocationState; | ||
var currentState = getLocationState(); | ||
var currentValue = itemName in currentState ? currentState[itemName] : defaultValue; | ||
if (typeof newValueOrFn === 'function') { | ||
// @ts-ignore | ||
newValue = newValueOrFn(currentValue); | ||
} | ||
else { | ||
newValue = newValueOrFn; | ||
} | ||
var newValue = reducer(currentValue, action); | ||
if (newValue === defaultValue) { | ||
@@ -290,15 +282,82 @@ return resetLocationStateItem(opts); | ||
_a); | ||
setLocationState(__assign(__assign({}, getLocationState()), stateExtendOverwrite), opts); | ||
}, [defaultValue, itemName, resetLocationStateItem]); | ||
setLocationState(__assign(__assign({}, currentState), stateExtendOverwrite), opts); | ||
}, [defaultValue, itemName, ref, resetLocationStateItem]); | ||
return [value, dispatchAction]; | ||
} | ||
var locationStateOptsDefaults$1 = Object.freeze({}); | ||
function useLocationState(itemName, initialState, opts) { | ||
if (opts === void 0) { opts = locationStateOptsDefaults$1; } | ||
if (typeof initialState === 'function') { | ||
return useLocationReducer(itemName, stateReducer, undefined, initialState, opts); | ||
} | ||
return useLocationReducer(itemName, stateReducer, initialState, opts); | ||
} | ||
function stateReducer(prevState, action) { | ||
if (action && typeof action === 'function') { | ||
return action(prevState); | ||
} | ||
return action; | ||
} | ||
function useQueryStateObj(defaultQueryState, queryStateOpts) { | ||
var queryStringInterface = queryStateOpts.queryStringInterface; | ||
var hashQSI = useHashQueryStringInterface(queryStringInterface && { disabled: true }); | ||
var activeQSI = queryStringInterface || hashQSI; | ||
var queryString = activeQSI.getQueryString(); | ||
var _a = react.useState(), setLatestMergedQueryString = _a[1]; | ||
var queryState = react.useMemo(function () { return (__assign(__assign({}, defaultQueryState), queryStateCore.parseQueryState(queryString))); }, [defaultQueryState, queryString]); | ||
var ref = react.useRef({ | ||
defaultQueryState: defaultQueryState, | ||
queryStateOpts: queryStateOpts, | ||
activeQSI: activeQSI, | ||
}); | ||
var setQueryState = react.useCallback(function (newState, opts) { | ||
var _a = ref.current, defaultQueryState = _a.defaultQueryState, queryStateOpts = _a.queryStateOpts, activeQSI = _a.activeQSI; | ||
var _b = queryStateOpts.stripDefaults, stripDefaults = _b === void 0 ? true : _b; | ||
var stripOverwrite = {}; | ||
// when a params are set to the same value as in the defaults | ||
// we remove them to avoid having two URLs reproducing the same state unless stripDefaults === false | ||
if (stripDefaults) { | ||
Object.entries(newState).forEach(function (_a) { | ||
var key = _a[0]; | ||
if (defaultQueryState[key] === newState[key]) { | ||
stripOverwrite[key] = null; | ||
} | ||
}); | ||
} | ||
// retrieve the last value (by re-executing the search getter) | ||
var currentQueryState = __assign(__assign({}, defaultQueryState), queryStateCore.parseQueryState(activeQSI.getQueryString())); | ||
var mergedQueryString = queryStateCore.createMergedQuery(currentQueryState || {}, newState, stripOverwrite); | ||
activeQSI.setQueryString(mergedQueryString, opts || {}); | ||
// triggers an update (in case the QueryStringInterface misses to do so) | ||
setLatestMergedQueryString(mergedQueryString); | ||
}, []); | ||
react.useEffect(function () { | ||
ref.current = { | ||
activeLSI: activeLSI, | ||
defaultQueryState: defaultQueryState, | ||
queryStateOpts: queryStateOpts, | ||
activeQSI: activeQSI, | ||
}; | ||
}); | ||
return [value, setLocationStateItem]; | ||
return [queryState, setQueryState]; | ||
} | ||
function useHashQueryStateObj(defaultQueryState, queryStateOpts) { | ||
if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
var hashQSI = useHashQueryStringInterface(); | ||
return useQueryStateObj(defaultQueryState, __assign(__assign({}, queryStateOpts), { queryStringInterface: hashQSI })); | ||
} | ||
function useHashQueryState(itemName, defaultValue, queryStateOpts) { | ||
if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
var hashQSI = useHashQueryStringInterface(); | ||
return useQueryState(itemName, defaultValue, __assign(__assign({}, queryStateOpts), { queryStringInterface: hashQSI })); | ||
} | ||
exports.LOCATION_STATE_KEY = LOCATION_STATE_KEY; | ||
exports.useHashQueryState = useHashQueryState; | ||
exports.useHashQueryStateObj = useHashQueryStateObj; | ||
exports.useLocationReducer = useLocationReducer; | ||
exports.useLocationState = useLocationState; | ||
exports.useQueryReducer = useQueryReducer; | ||
exports.useQueryState = useQueryState; |
export * from './useQueryState/useQueryState.types'; | ||
export * from './useLocationState/useLocationState.types'; | ||
export { default as useQueryState } from './useQueryState/useQueryState'; | ||
export { default as useHashQueryState } from './useQueryState/useHashQueryState'; | ||
export { default as useLocationState } from './useLocationState/useLocationState'; | ||
export * from './types/sharedTypes'; | ||
export * from './useQueryState/useQueryState'; | ||
export * from './useQueryState/useQueryReducer'; | ||
export * from './useLocationState/useLocationState'; | ||
export * from './useLocationState/useLocationReducer'; | ||
export * from './useQueryState/useHashQueryState'; |
@@ -1,3 +0,3 @@ | ||
import { useMemo, useState, useEffect, useRef, useCallback } from 'react'; | ||
import { parseQueryState, createMergedQuery, toQueryStateValue, parseQueryStateValue } from 'query-state-core'; | ||
import { useMemo, useState, useEffect, useRef, useLayoutEffect, useCallback } from 'react'; | ||
import { toQueryStateValue, parseQueryState, createMergedQuery, parseQueryStateValue } from 'query-state-core'; | ||
@@ -7,14 +7,14 @@ var LOCATION_STATE_KEY = '__useLocationState'; | ||
/*! ***************************************************************************** | ||
Copyright (c) Microsoft Corporation. All rights reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
this file except in compliance with the License. You may obtain a copy of the | ||
License at http://www.apache.org/licenses/LICENSE-2.0 | ||
Copyright (c) Microsoft Corporation. | ||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED | ||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
MERCHANTABLITY OR NON-INFRINGEMENT. | ||
Permission to use, copy, modify, and/or distribute this software for any | ||
purpose with or without fee is hereby granted. | ||
See the Apache Version 2.0 License for specific language governing permissions | ||
and limitations under the License. | ||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | ||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | ||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | ||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
PERFORMANCE OF THIS SOFTWARE. | ||
***************************************************************************** */ | ||
@@ -71,71 +71,54 @@ | ||
function useQueryStateObj(defaultQueryState, queryStateOpts) { | ||
var queryStringInterface = queryStateOpts.queryStringInterface; | ||
var hashQSI = useHashQueryStringInterface(queryStringInterface && { disabled: true }); | ||
var activeQSI = queryStringInterface || hashQSI; | ||
var queryString = activeQSI.getQueryString(); | ||
var _a = useState(), setLatestMergedQueryString = _a[1]; | ||
var queryState = useMemo(function () { return (__assign(__assign({}, defaultQueryState), parseQueryState(queryString))); }, [defaultQueryState, queryString]); | ||
var ref = useRef({ | ||
defaultQueryState: defaultQueryState, | ||
queryStateOpts: queryStateOpts, | ||
activeQSI: activeQSI, | ||
}); | ||
var setQueryState = useCallback(function (newState, opts) { | ||
var _a = ref.current, defaultQueryState = _a.defaultQueryState, queryStateOpts = _a.queryStateOpts, activeQSI = _a.activeQSI; | ||
var _b = queryStateOpts.stripDefaults, stripDefaults = _b === void 0 ? true : _b; | ||
var stripOverwrite = {}; | ||
// when a params are set to the same value as in the defaults | ||
// we remove them to avoid having two URLs reproducing the same state unless stripDefaults === false | ||
if (stripDefaults) { | ||
Object.entries(newState).forEach(function (_a) { | ||
var key = _a[0]; | ||
if (defaultQueryState[key] === newState[key]) { | ||
stripOverwrite[key] = null; | ||
} | ||
}); | ||
} | ||
// retrieve the last value (by re-executing the search getter) | ||
var currentQueryState = __assign(__assign({}, defaultQueryState), parseQueryState(activeQSI.getQueryString())); | ||
var mergedQueryString = createMergedQuery(currentQueryState || {}, newState, stripOverwrite); | ||
activeQSI.setQueryString(mergedQueryString, opts || {}); | ||
// triggers an update (in case the QueryStringInterface misses to do so) | ||
setLatestMergedQueryString(mergedQueryString); | ||
}, []); | ||
useEffect(function () { | ||
ref.current = { | ||
defaultQueryState: defaultQueryState, | ||
queryStateOpts: queryStateOpts, | ||
activeQSI: activeQSI, | ||
}; | ||
}); | ||
return [queryState, setQueryState]; | ||
function useRefLatest(value) { | ||
var ref = useRef(value); | ||
useLayoutEffect(function () { | ||
ref.current = value; | ||
}, [value]); | ||
return ref; | ||
} | ||
function sameAsJsonString(compareValueA, compareValueB) { | ||
return JSON.stringify(compareValueA) === JSON.stringify(compareValueB); | ||
} | ||
function useQueryState(itemName, defaultValue, queryStateOpts) { | ||
if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
defaultValue = useState(defaultValue)[0]; | ||
var defaultQueryStateValue = toQueryStateValue(defaultValue); | ||
var defaultQueryState = useMemo(function () { | ||
var _a; | ||
return defaultQueryStateValue | ||
? (_a = {}, | ||
_a[itemName] = defaultQueryStateValue, | ||
_a) : {}; | ||
}, [itemName, defaultQueryStateValue]); | ||
var queryStateOptsDefaults = Object.freeze({}); | ||
function useQueryReducer(itemName, reducer, initialStateOrInitialArg, initStateFnOrOpts, queryStateOpts) { | ||
var _a; | ||
var mergedQueryStateOpts = Object.assign({}, queryStateOptsDefaults, queryStateOpts, typeof initStateFnOrOpts === 'object' ? initStateFnOrOpts : null); | ||
var queryStringInterface = mergedQueryStateOpts.queryStringInterface; | ||
var hashQSI = useHashQueryStringInterface(queryStringInterface ? { disabled: true } : undefined); | ||
var activeQSI = queryStringInterface || hashQSI; | ||
// itemName & defaultValue is not allowed to be changed after init | ||
var defaultValue = useState(function () { | ||
return initStateFnOrOpts && typeof initStateFnOrOpts === 'function' | ||
? initStateFnOrOpts(initialStateOrInitialArg) | ||
: initialStateOrInitialArg; | ||
})[0]; | ||
var defaultQueryStateValue = useMemo(function () { return toQueryStateValue(defaultValue); }, [defaultValue]); | ||
if (defaultQueryStateValue === null) { | ||
throw new Error('unsupported defaultValue'); | ||
} | ||
var _a = useQueryStateObj(defaultQueryState, queryStateOpts), queryState = _a[0], setQueryState = _a[1]; | ||
var setQueryStateItem = useCallback(function (newValue, opts) { | ||
var ref = useRefLatest({ | ||
activeQSI: activeQSI, | ||
defaultValue: defaultValue, | ||
mergedQueryStateOpts: mergedQueryStateOpts, | ||
reducer: reducer, | ||
}); | ||
var resetQueryStateItem = useCallback(function (opts) { | ||
var _a; | ||
// stringify the given value (or array of strings) | ||
var activeQSI = ref.current.activeQSI; | ||
var currentState = parseQueryState(activeQSI.getQueryString()) || {}; | ||
var newState = __assign(__assign({}, currentState), (_a = {}, _a[itemName] = null, _a)); | ||
activeQSI.setQueryString(createMergedQuery(newState), opts); | ||
setR(function (rC) { return rC + 1; }); | ||
}, [itemName, ref]); | ||
var _b = useState(0), setR = _b[1]; | ||
var dispatch = useCallback(function (action, opts) { | ||
var _a; | ||
if (opts === void 0) { opts = {}; } | ||
var _b = ref.current, activeQSI = _b.activeQSI, defaultValue = _b.defaultValue, mergedQueryStateOpts = _b.mergedQueryStateOpts, reducer = _b.reducer; | ||
var _c = mergedQueryStateOpts.stripDefaults, stripDefaults = _c === void 0 ? true : _c; | ||
var currentState = parseQueryState(activeQSI.getQueryString()) || {}; | ||
var currentValue = itemName in currentState | ||
? parseQueryStateValue(currentState[itemName], defaultValue) | ||
: defaultValue; | ||
var newValue = reducer(currentValue !== null && currentValue !== void 0 ? currentValue : defaultValue, action); | ||
var newQueryStateValue = toQueryStateValue(newValue); | ||
// warn when value type is not supported (do not warn when null was passed explicitly) | ||
if ((newQueryStateValue === null && newValue !== newQueryStateValue) || | ||
!(newQueryStateValue !== null && | ||
typeof parseQueryStateValue(newQueryStateValue, defaultValue) === typeof defaultValue)) { | ||
if (newQueryStateValue === null) { | ||
console.warn('value of ' + | ||
@@ -145,32 +128,40 @@ JSON.stringify(newValue) + | ||
itemName + | ||
'" will reset to default value', defaultValue); | ||
newQueryStateValue = null; | ||
'" will reset to default value of:', defaultValue); | ||
} | ||
// when new value is equal to default, we call setQueryState with a null value to reset query string | ||
// arrays have to be compared json stringified, other values can compared by value | ||
if (Array.isArray(defaultValue) && sameAsJsonString(newValue, defaultValue)) { | ||
newQueryStateValue = null; | ||
// when a params are set to the same value as in the defaults | ||
// we remove them to avoid having two URLs reproducing the same state unless stripDefaults === false | ||
if (stripDefaults) { | ||
if (Array.isArray(defaultValue) && sameAsJsonString(newValue, defaultValue)) { | ||
return resetQueryStateItem(opts); | ||
} | ||
else if (newValue === defaultValue) { | ||
return resetQueryStateItem(opts); | ||
} | ||
} | ||
else if (newValue === defaultValue) { | ||
newQueryStateValue = null; | ||
} | ||
setQueryState((_a = {}, _a[itemName] = newQueryStateValue, _a), opts); | ||
}, [defaultValue, itemName, setQueryState]); | ||
// fallback to default value | ||
var value = defaultValue; | ||
var queryStateItem = queryState[itemName]; | ||
var queryStateValue = null; | ||
if (queryStateItem || queryStateItem === '') { | ||
queryStateValue = parseQueryStateValue(queryStateItem, defaultValue); | ||
} | ||
if (queryStateValue !== null && typeof queryStateValue === typeof defaultValue) { | ||
value = queryStateValue; | ||
} | ||
return [value, setQueryStateItem]; | ||
activeQSI.setQueryString(createMergedQuery(__assign(__assign({}, currentState), (_a = {}, _a[itemName] = toQueryStateValue(newValue), _a))), opts); | ||
// force re-render | ||
setR(function (rC) { return rC + 1; }); | ||
}, [itemName, ref, resetQueryStateItem]); | ||
var currentState = parseQueryState(activeQSI.getQueryString()) || {}; | ||
var currentValue = (_a = (itemName in currentState | ||
? parseQueryStateValue(currentState[itemName], defaultValue) | ||
: defaultValue)) !== null && _a !== void 0 ? _a : defaultValue; | ||
return [currentValue, dispatch]; | ||
} | ||
function sameAsJsonString(compareValueA, compareValueB) { | ||
return JSON.stringify(compareValueA) === JSON.stringify(compareValueB); | ||
} | ||
function useHashQueryState(itemName, defaultValue, queryStateOpts) { | ||
function useQueryState(itemName, initialState, queryStateOpts) { | ||
if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
var hashQSI = useHashQueryStringInterface(); | ||
return useQueryState(itemName, defaultValue, __assign(__assign({}, queryStateOpts), { queryStringInterface: hashQSI })); | ||
var reducer = useCallback(function (prevState, action) { | ||
if (action && typeof action === 'function') { | ||
return action(prevState); | ||
} | ||
return action; | ||
}, []); | ||
if (typeof initialState === 'function') { | ||
return useQueryReducer(itemName, reducer, undefined, initialState, queryStateOpts); | ||
} | ||
return useQueryReducer(itemName, reducer, initialState, queryStateOpts); | ||
} | ||
@@ -213,7 +204,7 @@ | ||
return; | ||
var hashChangeHandler = function () { | ||
var popstateHandler = function () { | ||
setR(function (r) { return r + 1; }); | ||
}; | ||
window.addEventListener('popstate', hashChangeHandler, false); | ||
return function () { return window.removeEventListener('popstate', hashChangeHandler, false); }; | ||
window.addEventListener('popstate', popstateHandler, false); | ||
return function () { return window.removeEventListener('popstate', popstateHandler, false); }; | ||
}, [enabled]); | ||
@@ -225,5 +216,12 @@ return locationStateInterface; | ||
var locationStateOptsDefaults = Object.freeze({}); | ||
function useLocationState(itemName, defaultValue, _a) { | ||
var locationStateInterface = (_a === void 0 ? locationStateOptsDefaults : _a).locationStateInterface; | ||
defaultValue = useState(defaultValue)[0]; | ||
function useLocationReducer(itemName, reducer, initialStateOrInitialArg, maybeInitStateFnOrOpts, opts) { | ||
var locationStateInterface = (opts || | ||
(typeof maybeInitStateFnOrOpts === 'object' && maybeInitStateFnOrOpts) || | ||
locationStateOptsDefaults).locationStateInterface; | ||
// itemName & defaultValue is not allowed to be changed after init | ||
var defaultValue = useState(function () { | ||
return maybeInitStateFnOrOpts && typeof maybeInitStateFnOrOpts === 'function' | ||
? maybeInitStateFnOrOpts(initialStateOrInitialArg) | ||
: initialStateOrInitialArg; | ||
})[0]; | ||
// throw for invalid values like functions | ||
@@ -234,3 +232,3 @@ if (!validTypes.includes(typeof defaultValue)) { | ||
itemName = useState(function () { | ||
var suffixObscurer = typeof btoa !== "undefined" ? btoa : (function (s) { return s; }); | ||
var suffixObscurer = typeof btoa !== 'undefined' ? btoa : function (s) { return s; }; | ||
var suffix = suffixObscurer(Array.isArray(defaultValue) ? 'array' : typeof defaultValue).replace(/=/g, ''); | ||
@@ -242,4 +240,5 @@ return itemName + "__" + suffix; | ||
var activeLSI = locationStateInterface || standardLSI; | ||
var ref = useRef({ | ||
var ref = useRefLatest({ | ||
activeLSI: activeLSI, | ||
reducer: reducer, | ||
}); | ||
@@ -259,17 +258,10 @@ var currentState = activeLSI.getLocationState(); | ||
activeLSI.setLocationState(newState, opts); | ||
}, [itemName]); | ||
var setLocationStateItem = useCallback(function (newValueOrFn, opts) { | ||
}, [itemName, ref]); | ||
var dispatchAction = useCallback(function (action, opts) { | ||
var _a; | ||
if (opts === void 0) { opts = {}; } | ||
var _b = ref.current.activeLSI, getLocationState = _b.getLocationState, setLocationState = _b.setLocationState; | ||
var newValue; | ||
var _b = ref.current, reducer = _b.reducer, _c = _b.activeLSI, getLocationState = _c.getLocationState, setLocationState = _c.setLocationState; | ||
var currentState = getLocationState(); | ||
var currentValue = itemName in currentState ? currentState[itemName] : defaultValue; | ||
if (typeof newValueOrFn === 'function') { | ||
// @ts-ignore | ||
newValue = newValueOrFn(currentValue); | ||
} | ||
else { | ||
newValue = newValueOrFn; | ||
} | ||
var newValue = reducer(currentValue, action); | ||
if (newValue === defaultValue) { | ||
@@ -286,12 +278,76 @@ return resetLocationStateItem(opts); | ||
_a); | ||
setLocationState(__assign(__assign({}, getLocationState()), stateExtendOverwrite), opts); | ||
}, [defaultValue, itemName, resetLocationStateItem]); | ||
setLocationState(__assign(__assign({}, currentState), stateExtendOverwrite), opts); | ||
}, [defaultValue, itemName, ref, resetLocationStateItem]); | ||
return [value, dispatchAction]; | ||
} | ||
var locationStateOptsDefaults$1 = Object.freeze({}); | ||
function useLocationState(itemName, initialState, opts) { | ||
if (opts === void 0) { opts = locationStateOptsDefaults$1; } | ||
if (typeof initialState === 'function') { | ||
return useLocationReducer(itemName, stateReducer, undefined, initialState, opts); | ||
} | ||
return useLocationReducer(itemName, stateReducer, initialState, opts); | ||
} | ||
function stateReducer(prevState, action) { | ||
if (action && typeof action === 'function') { | ||
return action(prevState); | ||
} | ||
return action; | ||
} | ||
function useQueryStateObj(defaultQueryState, queryStateOpts) { | ||
var queryStringInterface = queryStateOpts.queryStringInterface; | ||
var hashQSI = useHashQueryStringInterface(queryStringInterface && { disabled: true }); | ||
var activeQSI = queryStringInterface || hashQSI; | ||
var queryString = activeQSI.getQueryString(); | ||
var _a = useState(), setLatestMergedQueryString = _a[1]; | ||
var queryState = useMemo(function () { return (__assign(__assign({}, defaultQueryState), parseQueryState(queryString))); }, [defaultQueryState, queryString]); | ||
var ref = useRef({ | ||
defaultQueryState: defaultQueryState, | ||
queryStateOpts: queryStateOpts, | ||
activeQSI: activeQSI, | ||
}); | ||
var setQueryState = useCallback(function (newState, opts) { | ||
var _a = ref.current, defaultQueryState = _a.defaultQueryState, queryStateOpts = _a.queryStateOpts, activeQSI = _a.activeQSI; | ||
var _b = queryStateOpts.stripDefaults, stripDefaults = _b === void 0 ? true : _b; | ||
var stripOverwrite = {}; | ||
// when a params are set to the same value as in the defaults | ||
// we remove them to avoid having two URLs reproducing the same state unless stripDefaults === false | ||
if (stripDefaults) { | ||
Object.entries(newState).forEach(function (_a) { | ||
var key = _a[0]; | ||
if (defaultQueryState[key] === newState[key]) { | ||
stripOverwrite[key] = null; | ||
} | ||
}); | ||
} | ||
// retrieve the last value (by re-executing the search getter) | ||
var currentQueryState = __assign(__assign({}, defaultQueryState), parseQueryState(activeQSI.getQueryString())); | ||
var mergedQueryString = createMergedQuery(currentQueryState || {}, newState, stripOverwrite); | ||
activeQSI.setQueryString(mergedQueryString, opts || {}); | ||
// triggers an update (in case the QueryStringInterface misses to do so) | ||
setLatestMergedQueryString(mergedQueryString); | ||
}, []); | ||
useEffect(function () { | ||
ref.current = { | ||
activeLSI: activeLSI, | ||
defaultQueryState: defaultQueryState, | ||
queryStateOpts: queryStateOpts, | ||
activeQSI: activeQSI, | ||
}; | ||
}); | ||
return [value, setLocationStateItem]; | ||
return [queryState, setQueryState]; | ||
} | ||
export { LOCATION_STATE_KEY, useHashQueryState, useLocationState, useQueryState }; | ||
function useHashQueryStateObj(defaultQueryState, queryStateOpts) { | ||
if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
var hashQSI = useHashQueryStringInterface(); | ||
return useQueryStateObj(defaultQueryState, __assign(__assign({}, queryStateOpts), { queryStringInterface: hashQSI })); | ||
} | ||
function useHashQueryState(itemName, defaultValue, queryStateOpts) { | ||
if (queryStateOpts === void 0) { queryStateOpts = {}; } | ||
var hashQSI = useHashQueryStringInterface(); | ||
return useQueryState(itemName, defaultValue, __assign(__assign({}, queryStateOpts), { queryStringInterface: hashQSI })); | ||
} | ||
export { LOCATION_STATE_KEY, useHashQueryState, useHashQueryStateObj, useLocationReducer, useLocationState, useQueryReducer, useQueryState }; |
@@ -1,2 +0,4 @@ | ||
import { LocationStateOpts, SetLocationState } from './useLocationState.types'; | ||
export default function useLocationState<S>(itemName: string, defaultValue: S | (() => S), { locationStateInterface }?: LocationStateOpts): [S, SetLocationState<S>]; | ||
import { LocationStateOpts } from './useLocationState.types'; | ||
import { LocationDispatch } from './useLocationReducer'; | ||
import { LazyValueFn, SetStateAction } from '../types/sharedTypes'; | ||
export declare function useLocationState<S>(itemName: string, initialState: S | LazyValueFn<S>, opts?: LocationStateOpts): [S, LocationDispatch<SetStateAction<S>>]; |
@@ -0,1 +1,2 @@ | ||
import { SetStateAction } from '../types/sharedTypes'; | ||
export declare const LOCATION_STATE_KEY = "__useLocationState"; | ||
@@ -14,4 +15,2 @@ export declare type LocationStateValue<K = unknown> = string | number | boolean | undefined | Date | Array<K>; | ||
} | ||
declare type SetStateAction<S> = S | ((prevState: S) => S); | ||
export declare type SetLocationState<T> = (newValue: SetStateAction<T>, opts?: SetLocationStateOptions) => void; | ||
export {}; |
import { QueryState } from 'query-state-core'; | ||
import { QueryStateOptsSetInterface } from './useQueryState.types'; | ||
import { QueryStateOptsSetInterface, QueryStateType } from './useQueryState.types'; | ||
export declare function useHashQueryStateObj<T extends QueryState>(defaultQueryState: T, queryStateOpts?: QueryStateOptsSetInterface): [Record<string, import("query-state-core").QueryStateValue>, import("./useQueryState.types").SetQueryStateFn<T>]; | ||
export default function useHashQueryState<T>(itemName: string, defaultValue: T, queryStateOpts?: QueryStateOptsSetInterface): [T, import("./useQueryState.types").SetQueryStateItemFn<T>]; | ||
export declare function useHashQueryState<T extends QueryStateType>(itemName: string, defaultValue: T, queryStateOpts?: QueryStateOptsSetInterface): [T, import("./useQueryReducer").QueryDispatch<import("../use-location-state").SetStateAction<T>>]; |
@@ -1,2 +0,4 @@ | ||
import { QueryStateOpts, SetQueryStateItemFn } from './useQueryState.types'; | ||
export default function useQueryState<T>(itemName: string, defaultValue: T, queryStateOpts?: QueryStateOpts): [T, SetQueryStateItemFn<T>]; | ||
import { QueryStateOpts } from './useQueryState.types'; | ||
import { QueryDispatch } from './useQueryReducer'; | ||
import { LazyValueFn, SetStateAction } from '../types/sharedTypes'; | ||
export declare function useQueryState<S>(itemName: string, initialState: S | LazyValueFn<S>, queryStateOpts?: QueryStateOpts): [S, QueryDispatch<SetStateAction<S>>]; |
import { QueryStateMerge } from 'query-state-core'; | ||
export declare type QueryString = string; | ||
export declare type SetQueryStateFn<T> = (newState: QueryStateMerge, opts?: SetQueryStringOptions) => void; | ||
export declare type SetQueryStateItemFn<T> = (newValue: T, opts?: SetQueryStringOptions) => void; | ||
export interface QueryStringInterface { | ||
@@ -19,1 +18,2 @@ getQueryString: () => QueryString; | ||
}; | ||
export declare type QueryStateType = string | number | boolean | Date | string[]; |
import { QueryState } from 'query-state-core'; | ||
import { QueryStateOpts, SetQueryStateFn } from './useQueryState.types'; | ||
export default function useQueryStateObj<T extends QueryState>(defaultQueryState: T, queryStateOpts: QueryStateOpts): [QueryState, SetQueryStateFn<T>]; | ||
export declare function useQueryStateObj<T extends QueryState>(defaultQueryState: T, queryStateOpts: QueryStateOpts): [QueryState, SetQueryStateFn<T>]; |
@@ -11,5 +11,5 @@ { | ||
"dependencies": { | ||
"query-state-core": "^2.3.0" | ||
"query-state-core": "^2.4.0" | ||
}, | ||
"version": "2.3.1", | ||
"version": "2.4.0", | ||
"author": "Felix Leupold <felix@xiel.de>", | ||
@@ -21,6 +21,6 @@ "homepage": "https://github.com/xiel/use-location-state", | ||
"react": "^16.9.0", | ||
"rollup": "^1.19.3", | ||
"rollup-plugin-typescript2": "^0.24.0", | ||
"tslib": "^1.9.3", | ||
"typescript": "^3.6.3" | ||
"rollup": ">=2.0.0", | ||
"rollup-plugin-typescript2": ">=0.26.0", | ||
"tslib": "*", | ||
"typescript": "*" | ||
}, | ||
@@ -43,3 +43,3 @@ "files": [ | ||
}, | ||
"gitHead": "2248d0e2266c0e971551fe70bcf82fb6941ff2c2" | ||
"gitHead": "378cd4bffb30a0f96f0d68b1959fb5050114a5cc" | ||
} |
@@ -1,5 +0,6 @@ | ||
<h1 style="width: 100%; text-align: center;"> { useLocationState, useQueryState }</h1> | ||
<div style="width: 100%; text-align: center;"> | ||
<h1>{ useLocationState, useQueryState }</h1> | ||
</div> | ||
[![npm (tag)](https://img.shields.io/npm/v/use-location-state/latest.svg)](https://www.npmjs.com/package/use-location-state) | ||
[![Greenkeeper badge](https://badges.greenkeeper.io/xiel/use-location-state.svg)](https://greenkeeper.io/) | ||
[![codecov badge](https://img.shields.io/codecov/c/github/xiel/use-location-state/master.svg?color=hotpink)](https://codecov.io/gh/xiel/use-location-state) | ||
@@ -15,7 +16,7 @@ ![GitHub top language](https://img.shields.io/github/languages/top/xiel/use-location-state.svg) | ||
- makes it easy to share the application in a customizable state | ||
- __`useLocationState(name, defaultValue)`__ | ||
- **`useLocationState(name, defaultValue)`** | ||
- restores the latest value after navigation actions (back/forward), by keeping value in `history.state` | ||
- supported value types: `string | number | boolean | Date | Array | Object` | ||
- handles complex & nested values - all values that can be serialized are supported | ||
- __`useQueryState(name, defaultValue)`__ | ||
- **`useQueryState(name, defaultValue)`** | ||
- restores the latest value from URL (`location.href`) and after navigation actions (back/forward) | ||
@@ -25,3 +26,2 @@ - supported value types: `string | number | boolean | Date | string[]` | ||
- invalid entries from the query string are discarded and the component will receive the defaultValue instead | ||
@@ -36,9 +36,9 @@ <img style="display: block; margin: auto;" src="https://repository-images.githubusercontent.com/182417896/058a9d00-e2e1-11e9-8467-8923219ec500" /> | ||
Using __`react-router`__ or another popular router? For the best experience install one of the [router integrations](#router-integration-optional). | ||
Using **`react-router`** or another popular router? For the best experience install one of the [router integrations](#router-integration-optional). | ||
## Usage | ||
`useLocationState()` and `useQueryState()` work similar to the `useState()` [hook](https://reactjs.org/docs/hooks-overview.html#state-hook), as they also return the current value and a update function in a tuple `[currentValue, updateValueFn]`. | ||
`useLocationState()` and `useQueryState()` work similar to the `useState()` [hook](https://reactjs.org/docs/hooks-overview.html#state-hook), as they also return the current value and a update function in a tuple `[currentValue, updateValueFn]`. | ||
The *important difference* is that __you must pass a name__ before your __default value__ for your state. | ||
The _important difference_ is that **you must pass a name** before your **default value** for your state. | ||
@@ -63,2 +63,3 @@ ```javascript | ||
``` | ||
The updated state will be restored when the pages reloads and after the user navigated to a new page and comes back using a back/forward action. | ||
@@ -68,3 +69,3 @@ | ||
`useQueryState()` is a great, when you want to store information about the current state of you app in the URL. | ||
`useQueryState()` is a great, when you want to store information about the current state of you app in the URL. | ||
@@ -74,2 +75,3 @@ ```javascript | ||
``` | ||
The name you pass will be used as a parameter name in the query string, when setting a new value: | ||
@@ -80,2 +82,3 @@ | ||
``` | ||
After calling the update function `setValue()` with a new value, the state will be saved withing the query string of the browser, so that the new state is reproducable after reloads or history navigation (using forward / back button) or by loading the same URL anywhere else. | ||
@@ -92,3 +95,3 @@ | ||
In cases where you want the updated state to be represented as a __new entry in the history__ you can pass a options object to the set function, with the method property set to `'push'`. | ||
In cases where you want the updated state to be represented as a **new entry in the history** you can pass a options object to the set function, with the method property set to `'push'`. | ||
@@ -102,2 +105,3 @@ ```javascript | ||
### Example | ||
```javascript | ||
@@ -110,3 +114,5 @@ import { useQueryState } from 'use-location-state' | ||
<div> | ||
<button type="button" onClick={() => setActive(!active)}>Toggle</button> | ||
<button type="button" onClick={() => setActive(!active)}> | ||
Toggle | ||
</button> | ||
{active && <p>Some active content</p>} | ||
@@ -117,2 +123,3 @@ </div> | ||
``` | ||
<a href="https://codesandbox.io/embed/zqm4o19yrx"> | ||
@@ -122,3 +129,2 @@ <img width="150" alt="Example in CodeSandbox" src="https://codesandbox.io/static/img/play-codesandbox.svg"> | ||
### Example with multiple useQueryState hooks in one component | ||
@@ -136,2 +142,3 @@ | ||
``` | ||
<a href="https://codesandbox.io/embed/github/xiel/use-location-state/tree/master/src/examples/use-location-state/?fontsize=14&module=%2Fsrc%2Fpages%2FQueryStateDemo.tsx"> | ||
@@ -145,3 +152,3 @@ <img width="150" alt="Example in CodeSandbox" src="https://codesandbox.io/static/img/play-codesandbox.svg"> | ||
We plan to provide clean and easy-to-use integrations for all popular routers. | ||
We plan to provide clean and easy-to-use integrations for all popular routers. | ||
At the moment we provide integrations for: | ||
@@ -154,9 +161,13 @@ | ||
``` | ||
```javascript | ||
import { useLocationState, useQueryState } from 'react-router-use-location-state' | ||
``` | ||
Usage works the same as described above, except that the URL will look like this now: | ||
```javascript | ||
http://localhost:3000/?itemName=different+value | ||
``` | ||
<a href="https://codesandbox.io/s/github/xiel/use-location-state/tree/master/src/examples/react-router-use-location-state?fontsize=14&module=%2Fsrc%2Fpages%2FQueryStateDemo.tsx"> | ||
@@ -166,2 +177,15 @@ <img width="150" alt="Edit react-router-use-location-state-example" src="https://codesandbox.io/static/img/play-codesandbox.svg"> | ||
### Gatsby & @reach/router | ||
Gatsby & Reach Router are supported. Gatsby currently always scrolls up on location (state) changes. To keep the scroll position, when you update location state using the update function of `useLocationState`, add these lines to the **gatsby-browser.js** file in gatsby root folder. | ||
```javascript | ||
// keeps same scroll pos when history state is pushed/replaced (same location === same position) | ||
// see: https://www.gatsbyjs.org/docs/browser-apis/#shouldUpdateScroll | ||
exports.shouldUpdateScroll = ({ routerProps, getSavedScrollPosition }) => { | ||
const currentPosition = getSavedScrollPosition(routerProps.location) | ||
return currentPosition || true | ||
} | ||
``` | ||
### More routers soon - work in progress | ||
@@ -176,4 +200,4 @@ | ||
```javascript | ||
import 'react-app-polyfill/ie11'; | ||
import 'react-app-polyfill/stable'; | ||
import 'react-app-polyfill/ie11' | ||
import 'react-app-polyfill/stable' | ||
``` |
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
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
52247
31
0
767
187
Updatedquery-state-core@^2.4.0