Comparing version 1.1.0 to 1.2.0
@@ -1,3 +0,3 @@ | ||
export declare const useLocalStorage: <T = StoredData>(key: StorageKey, initialValue?: T | undefined) => { | ||
mergeState: (state: Record<string, any>) => void; | ||
export declare const useLocalStorage: <T = StoredData>(key: StorageKey, initialValue?: T | undefined, version?: number | undefined) => { | ||
mergeState: (state: Record<string, unknown>) => void; | ||
resetValue: () => void; | ||
@@ -7,5 +7,6 @@ setValue: (value: T) => void; | ||
value?: T | undefined; | ||
version?: number | undefined; | ||
}; | ||
export declare const useSessionStorage: <T = StoredData>(key: StorageKey, initialValue?: T | undefined) => { | ||
mergeState: (state: Record<string, any>) => void; | ||
export declare const useSessionStorage: <T = StoredData>(key: StorageKey, initialValue?: T | undefined, version?: number | undefined) => { | ||
mergeState: (state: Record<string, unknown>) => void; | ||
resetValue: () => void; | ||
@@ -15,3 +16,4 @@ setValue: (value: T) => void; | ||
value?: T | undefined; | ||
version?: number | undefined; | ||
}; | ||
//# sourceMappingURL=useStorage.d.ts.map |
@@ -5,20 +5,22 @@ "use strict"; | ||
var react_1 = require("react"); | ||
var storageEvent_1 = require("./storageEvent"); | ||
var utils_1 = require("./utils"); | ||
var useStorage = function (storageType, key, initialValue) { | ||
if (utils_1.isServerSide()) { | ||
return { | ||
mergeState: utils_1.noop, | ||
resetValue: utils_1.noop, | ||
setValue: utils_1.noop, | ||
value: initialValue, | ||
}; | ||
} | ||
var _a = react_1.useState(function () { | ||
var item = utils_1.safeGetStorageValue(storageType, key); | ||
var useStorage = function (storageType, key, initialValue, version) { | ||
var ssr = (0, utils_1.isServerSide)(); | ||
var _a = (0, react_1.useState)(function () { | ||
if (ssr) | ||
return { data: initialValue }; | ||
var item = (0, utils_1.safeGetStorageValue)(storageType, key); | ||
// invalidate the stored data if the version has changed | ||
var hasVersion = typeof version !== 'undefined'; | ||
var storedVersionMismatch = hasVersion && | ||
(typeof item.version === 'undefined' || item.version !== version); | ||
if (storedVersionMismatch) { | ||
window[storageType].removeItem(key); | ||
return { data: initialValue }; | ||
} | ||
return (item === null || item === void 0 ? void 0 : item.data) ? item : { data: initialValue }; | ||
}), storedValue = _a[0], setStoredValue = _a[1]; | ||
var mergeState = function (state) { | ||
var mergeState = (0, react_1.useCallback)(function (state) { | ||
var ts = new Date(); | ||
var currentState = utils_1.isObject(storedValue.data) ? storedValue.data : {}; | ||
var currentState = (0, utils_1.isObject)(storedValue.data) ? storedValue.data : {}; | ||
var updatedState = Object.assign(currentState, state); | ||
@@ -28,10 +30,11 @@ setStoredValue({ | ||
ts: ts, | ||
version: version, | ||
}); | ||
utils_1.safeSetStorageValue(storageType, key, updatedState, ts); | ||
}; | ||
var resetValue = function () { | ||
(0, utils_1.safeSetStorageValue)(storageType, key, updatedState, ts, version); | ||
}, [key, storageType, storedValue.data, version]); | ||
var resetValue = (0, react_1.useCallback)(function () { | ||
setStoredValue({}); | ||
window[storageType].removeItem(key); | ||
}; | ||
var setValue = function (value) { | ||
}, [key, storageType]); | ||
var setValue = (0, react_1.useCallback)(function (value) { | ||
var ts = new Date(); | ||
@@ -41,8 +44,35 @@ setStoredValue({ | ||
ts: ts, | ||
version: version, | ||
}); | ||
utils_1.safeSetStorageValue(storageType, key, value, ts); | ||
}; | ||
storageEvent_1.registerStorageEventHandler(key, function (newValue) { | ||
setStoredValue(newValue); | ||
}); | ||
(0, utils_1.safeSetStorageValue)(storageType, key, value, ts, version); | ||
}, [key, storageType, version]); | ||
(0, react_1.useEffect)(function () { | ||
if (ssr) | ||
return; | ||
var storageEventHandler = function (e) { | ||
var isTrusted = e.isTrusted, eventKey = e.key, newValue = e.newValue; | ||
if (isTrusted && eventKey === key) { | ||
if (newValue) { | ||
var structuredValue = JSON.parse(newValue); | ||
setStoredValue(structuredValue); | ||
} | ||
else { | ||
setStoredValue({}); | ||
} | ||
} | ||
}; | ||
window.addEventListener('storage', storageEventHandler); | ||
return function () { | ||
window.removeEventListener('storage', storageEventHandler); | ||
}; | ||
}, [key, ssr]); | ||
if (ssr) { | ||
return { | ||
mergeState: utils_1.noop, | ||
resetValue: utils_1.noop, | ||
setValue: utils_1.noop, | ||
value: initialValue, | ||
version: version, | ||
}; | ||
} | ||
return { | ||
@@ -54,6 +84,11 @@ mergeState: mergeState, | ||
value: storedValue === null || storedValue === void 0 ? void 0 : storedValue.data, | ||
version: storedValue === null || storedValue === void 0 ? void 0 : storedValue.version, | ||
}; | ||
}; | ||
exports.useLocalStorage = function (key, initialValue) { return useStorage('localStorage', key, initialValue); }; | ||
exports.useSessionStorage = function (key, initialValue) { return useStorage('sessionStorage', key, initialValue); }; | ||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types | ||
var useLocalStorage = function (key, initialValue, version) { return useStorage('localStorage', key, initialValue, version); }; | ||
exports.useLocalStorage = useLocalStorage; | ||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types | ||
var useSessionStorage = function (key, initialValue, version) { return useStorage('sessionStorage', key, initialValue, version); }; | ||
exports.useSessionStorage = useSessionStorage; | ||
//# sourceMappingURL=useStorage.js.map |
@@ -5,3 +5,3 @@ export declare const isServerSide: () => boolean; | ||
export declare const safeGetStorageValue: <T>(storageType: StorageType, key: string) => StorageStructure<T>; | ||
export declare const safeSetStorageValue: <T>(storageType: StorageType, key: string, value: T, ts?: Date | undefined) => void; | ||
export declare const safeSetStorageValue: <T>(storageType: StorageType, key: string, value: T, ts?: Date | undefined, version?: number | undefined) => void; | ||
//# sourceMappingURL=utils.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.safeSetStorageValue = exports.safeGetStorageValue = exports.noop = exports.isObject = exports.isServerSide = void 0; | ||
exports.isServerSide = function () { return typeof window === 'undefined'; }; | ||
exports.isObject = function (obj) { | ||
return obj && obj.constructor === Object; | ||
var isServerSide = function () { return typeof window === 'undefined'; }; | ||
exports.isServerSide = isServerSide; | ||
var isObject = function (obj) { | ||
return !!obj && obj.constructor === Object; | ||
}; | ||
exports.noop = function () { return undefined; }; | ||
exports.safeGetStorageValue = function (storageType, key) { | ||
exports.isObject = isObject; | ||
var noop = function () { return undefined; }; | ||
exports.noop = noop; | ||
var safeGetStorageValue = function (storageType, key) { | ||
if ((0, exports.isServerSide)()) | ||
return {}; | ||
try { | ||
@@ -14,7 +19,9 @@ var value = window[storageType].getItem(key); | ||
if (value) { | ||
var _a = JSON.parse(value), data = _a.data, ts = _a.ts; | ||
var _a = JSON.parse(value), data = _a.data, version = _a.version, ts = _a.ts; | ||
var timestamp = new Date(ts); | ||
var versionNumber = typeof version !== 'undefined' ? Number(version) : undefined; | ||
parsedValue = { | ||
data: data, | ||
ts: timestamp, | ||
version: versionNumber, | ||
}; | ||
@@ -29,3 +36,6 @@ } | ||
}; | ||
exports.safeSetStorageValue = function (storageType, key, value, ts) { | ||
exports.safeGetStorageValue = safeGetStorageValue; | ||
var safeSetStorageValue = function (storageType, key, value, ts, version) { | ||
if ((0, exports.isServerSide)()) | ||
return; | ||
var timestamp = ts || new Date(); | ||
@@ -36,2 +46,3 @@ try { | ||
ts: timestamp, | ||
version: version, | ||
}); | ||
@@ -41,5 +52,6 @@ window[storageType].setItem(key, storedValue); | ||
catch (error) { | ||
console.log(error); | ||
console.error(error); | ||
} | ||
}; | ||
exports.safeSetStorageValue = safeSetStorageValue; | ||
//# sourceMappingURL=utils.js.map |
@@ -8,3 +8,3 @@ { | ||
"license": "MIT", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"main": "dist/index.js", | ||
@@ -41,40 +41,28 @@ "types": "dist/index.d.ts", | ||
"lint": "eslint ./src --ext js --ext ts --ext tsx --fix", | ||
"prepare": "npm run build", | ||
"test": "jest" | ||
"prepare": "npm run build && husky install", | ||
"test": "jest --coverage" | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged" | ||
} | ||
}, | ||
"lint-staged": { | ||
"*.@(js|ts|tsx)": [ | ||
"npm run lint", | ||
"npm run format" | ||
] | ||
}, | ||
"devDependencies": { | ||
"@testing-library/react-hooks": "3.4.2", | ||
"@types/jest": "26.0.14", | ||
"@types/react": "16.9.53", | ||
"@typescript-eslint/eslint-plugin": "4.4.1", | ||
"@typescript-eslint/parser": "4.4.1", | ||
"eslint": "7.11.0", | ||
"eslint-config-prettier": "6.13.0", | ||
"eslint-plugin-prettier": "3.1.4", | ||
"husky": "4.3.0", | ||
"jest": "26.5.3", | ||
"jest-localstorage-mock": "2.4.3", | ||
"lint-staged": "10.4.2", | ||
"mockdate": "3.0.2", | ||
"prettier": "2.1.2", | ||
"react": "16.14.0", | ||
"react-test-renderer": "16.14.0", | ||
"ts-jest": "26.4.1", | ||
"typescript": "4.0.3" | ||
"@testing-library/react-hooks": "7.0.2", | ||
"@types/jest": "27.0.1", | ||
"@types/react": "17.0.19", | ||
"@typescript-eslint/eslint-plugin": "4.30.0", | ||
"@typescript-eslint/parser": "4.30.0", | ||
"eslint": "7.32.0", | ||
"eslint-config-prettier": "8.3.0", | ||
"eslint-plugin-prettier": "4.0.0", | ||
"eslint-plugin-react-hooks": "4.2.0", | ||
"husky": "7.0.2", | ||
"jest": "27.1.0", | ||
"jest-localstorage-mock": "2.4.17", | ||
"lint-staged": "11.1.2", | ||
"mockdate": "3.0.5", | ||
"prettier": "2.3.2", | ||
"react-test-renderer": "17.0.2", | ||
"ts-jest": "27.0.5", | ||
"typescript": "4.4.2" | ||
}, | ||
"dependencies": {}, | ||
"peerDependencies": { | ||
"react": ">=16.8.0" | ||
"react": "^16.8.0 || ^17" | ||
} | ||
} |
@@ -21,4 +21,6 @@ # Haversack | ||
npm install --save haversack | ||
yarn add haversack | ||
```bash | ||
npm install --save haversack | ||
yarn add haversack | ||
``` | ||
@@ -76,4 +78,5 @@ ## Usage With React | ||
```jsx | ||
const defaultValue = 'bar'; | ||
function MyComponent() { | ||
const defaultValue = 'bar'; | ||
const { value } = useLocalStorage('foo', defaultValue); | ||
@@ -91,2 +94,24 @@ | ||
## Versioning and Cache Busting | ||
You can pass an optional number to the hook to apply a specific version to your stored data. If the structure of your data changes, users who have stored data from the previous structure can experience issues when the incompatible data is applied to the new structure. Think of the `version` param as a schema version for the data. | ||
```jsx | ||
const schemaVersion = 2; | ||
function MyComponent() { | ||
const { value } = useLocalStorage('foo', 'bar', schemaVersion); | ||
return ( | ||
<div> | ||
The stored value is {value} for version {schemaVersion}. If the user had | ||
data stored with a different schema version, that old data will be | ||
invalidated. | ||
</div> | ||
); | ||
} | ||
``` | ||
There is no enforcement of standards on the version number—Haversack will do a simple `===` equality check to determine if the version number has changed. Any change in version number, forward or backward, will cause the stored data to be deleted to await new data with the current version number. If previous data was stored without a version number, the data will be invalidated when a version number is introduced. | ||
## Reset the Stored Value | ||
@@ -168,5 +193,5 @@ | ||
## Storage event sync | ||
## Storage Event Sync | ||
Each time you implement a Haversack hook, an `onstorage` event handler is registered. Any instance of your component on alternate browser tabs will be notified that `localStorage` has changed, and update the `value` accordingly. | ||
Each time you implement a Haversack hook, a `storage` event handler is registered. Any instance of your component on alternate browser tabs will be notified that `localStorage` has changed, and update the `value` accordingly. | ||
@@ -173,0 +198,0 @@ ## Notes on Server-Side Rendering Compatibility |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
23286
169
209
15