UNPKG

use-store

Version:

Shared, persistable React.js useState() hook effect, no context required

198 lines (158 loc) 5.65 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.useStore = useStore; exports["default"] = exports.globalStore = exports.GlobalStore = exports.Store = void 0; var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = require("react"); var GLOBALSTORAGE_PREFIX = '!ush::'; var debounce = function debounce(func) { var delay = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100; var timer; return function () { var context = this; var args = arguments; clearTimeout(timer); timer = setTimeout(function () { return func.apply(context, args); }, delay); }; }; // https://stackoverflow.com/a/2117523/11599918 var uuid = function uuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : r & 0x3 | 0x8; return v.toString(16); }); }; // individual Store implementation for tracking values/setters var Store = function Store(_ref) { var _this = this; var _value = _ref.value, namespace = _ref.namespace, _options = _ref.options; (0, _classCallCheck2["default"])(this, Store); (0, _defineProperty2["default"])(this, "handleMessage", debounce(function (e) { if (!e.data || e.data.id === _this.id) { return; } _this.setState(e.data.message, { broadcast: false }); }, 300)); (0, _defineProperty2["default"])(this, "setState", function (value) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { broadcast: true }; _this.state = value; if (_this.options.persist) { try { localStorage.setItem(GLOBALSTORAGE_PREFIX + _this.namespace, JSON.stringify(value)); } catch (err) { console.warn("[use-store-hook]: failed to persist", { value: value, err: err }); } } _this.setters.forEach(function (setter) { return setter(_this.state); }); if (options.broadcast && _this.options.broadcast) { _this.channel.postMessage({ id: _this.id, message: value }); } }); this.state = _value; this.id = uuid(); if (_options.persist) { try { var stored = localStorage.getItem(GLOBALSTORAGE_PREFIX + namespace); if (stored !== null) { this.state = JSON.parse(stored); } } catch (err) {} } if (_options.broadcast && window.BroadcastChannel) { this.channel = new BroadcastChannel(GLOBALSTORAGE_PREFIX + namespace); this.channel.addEventListener('message', this.handleMessage); } this.options = _options; this.namespace = namespace; this.setters = []; }; // namespaced index of requested Stores exports.Store = Store; var GlobalStore = function GlobalStore() { var _this2 = this; (0, _classCallCheck2["default"])(this, GlobalStore); (0, _defineProperty2["default"])(this, "set", function (namespace, value) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; if (_this2.hasOwnProperty(namespace)) { _this2[namespace].setState(value); } else { _this2[namespace] = new Store({ value: value, options: options, namespace: namespace }); } }); (0, _defineProperty2["default"])(this, "clear", function (namespace) { localStorage.removeItem(GLOBALSTORAGE_PREFIX + namespace); }); (0, _defineProperty2["default"])(this, "persist", function () { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _this2.set.apply(_this2, args.concat([{ persist: true }])); }); }; // shared instantiation of GlobalStore exports.GlobalStore = GlobalStore; var globalStore = new GlobalStore(); // the actual hook exports.globalStore = globalStore; function useStore(namespace, value) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var whichStore = undefined; if (!namespace) { throw new Error('no namespace provided to useStore... try using useState() instead?'); } if (globalStore.hasOwnProperty(namespace)) { whichStore = globalStore[namespace]; } else { whichStore = globalStore[namespace] = new Store({ value: value, options: options, namespace: namespace }); } var _useState = (0, _react.useState)(whichStore.state), _useState2 = (0, _slicedToArray2["default"])(_useState, 2), state = _useState2[0], set = _useState2[1]; if (whichStore.setters.indexOf(set) === -1) { whichStore.setters.push(set); } (0, _react.useEffect)(function () { return function () { whichStore.setters = whichStore.setters.filter(function (setter) { return setter !== set; }); }; }, []); var magicSetter = function magicSetter(setter) { return function (e) { (0, _typeof2["default"])(e) === 'object' && (e.nativeEvent || e.constructor.name === 'SyntheticEvent') && e.target ? setter(e.target.value) : setter(e); }; }; return [state, magicSetter(whichStore.setState)]; } var _default = useStore; exports["default"] = _default;