UNPKG

dexie-react-hooks

Version:

React hooks for reactive data fetching using Dexie.js

159 lines (150 loc) 7.66 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('dexie'), require('react')) : typeof define === 'function' && define.amd ? define(['exports', 'dexie', 'react'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.DexieReactHooks = {}, global.Dexie, global.React)); })(this, (function (exports, dexie, React) { 'use strict'; function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var React__default = /*#__PURE__*/_interopDefaultLegacy(React); function useObservable(observableFactory, arg2, arg3) { // Resolve vars from overloading variants of this function: var deps; var defaultResult; if (typeof observableFactory === 'function') { deps = arg2 || []; defaultResult = arg3; } else { deps = []; defaultResult = arg2; } // Create a ref that keeps the state we need var monitor = React__default["default"].useRef({ hasResult: false, result: defaultResult, error: null, }); // We control when component should rerender. Make triggerUpdate // as examplified on React's docs at: // https://reactjs.org/docs/hooks-faq.html#is-there-something-like-forceupdate var _a = React__default["default"].useReducer(function (x) { return x + 1; }, 0); _a[0]; var triggerUpdate = _a[1]; // Memoize the observable based on deps var observable = React__default["default"].useMemo(function () { // Make it remember previous subscription's default value when // resubscribing. var observable = typeof observableFactory === 'function' ? observableFactory() : observableFactory; if (!observable || typeof observable.subscribe !== 'function') { if (observableFactory === observable) { throw new TypeError("Given argument to useObservable() was neither a valid observable nor a function."); } else { throw new TypeError("Observable factory given to useObservable() did not return a valid observable."); } } if (!monitor.current.hasResult && typeof window !== 'undefined' // Don't do this in SSR ) { // Optimize for BehaviorSubject and other observables implementing getValue(): if (typeof observable.hasValue !== 'function' || observable.hasValue()) { if (typeof observable.getValue === 'function') { monitor.current.result = observable.getValue(); monitor.current.hasResult = true; } else { // Find out if the observable has a current value: try get it by subscribing and // unsubscribing synchronously var subscription = observable.subscribe(function (val) { monitor.current.result = val; monitor.current.hasResult = true; }); // Unsubscribe directly. We only needed any synchronous value if it was possible. if (typeof subscription === 'function') { subscription(); } else { subscription.unsubscribe(); } } } } return observable; }, deps); // Integrate with react devtools: React__default["default"].useDebugValue(monitor.current.result); // Subscribe to the observable React__default["default"].useEffect(function () { var subscription = observable.subscribe(function (val) { var current = monitor.current; if (current.error !== null || current.result !== val) { current.error = null; current.result = val; current.hasResult = true; triggerUpdate(); } }, function (err) { var current = monitor.current; if (current.error !== err) { current.error = err; triggerUpdate(); } }); return typeof subscription === 'function' ? subscription // Support observables that return unsubscribe directly : subscription.unsubscribe.bind(subscription); }, deps); // Throw if observable has emitted error so that // an ErrorBoundrary can catch it if (monitor.current.error) throw monitor.current.error; // Return the current result return monitor.current.result; } function useLiveQuery(querier, deps, defaultResult) { return useObservable(function () { return dexie.liveQuery(querier); }, deps || [], defaultResult); } function usePermissions(firstArg, table, obj) { if (!firstArg) throw new TypeError("Invalid arguments to usePermissions(): undefined or null"); var db; if (arguments.length >= 3) { if (!('transaction' in firstArg)) { // Using ducktyping instead of instanceof in case there are multiple Dexie modules in app. // First arg is ensures first arg is a Dexie instance throw new TypeError("Invalid arguments to usePermission(db, table, obj): 1st arg must be a Dexie instance"); } if (typeof table !== 'string') throw new TypeError("Invalid arguments to usePermission(db, table, obj): 2nd arg must be string"); if (!obj || typeof obj !== 'object') throw new TypeError("Invalid arguments to usePermission(db, table, obj): 3rd arg must be an object"); db = firstArg; } else { if (firstArg instanceof dexie.Dexie) throw new TypeError("Invalid arguments to usePermission(db, table, obj): Missing table and obj arguments."); if (typeof firstArg.table === 'function' && typeof firstArg.db === 'object') { db = firstArg.db; obj = firstArg; table = firstArg.table(); } else { throw new TypeError("Invalid arguments to usePermissions(). " + "Expected usePermissions(entity: DexieCloudEntity) or " + "usePermissions(db: Dexie, table: string, obj: DexieCloudObject)"); } } if (!('cloud' in db)) throw new Error("usePermissions() is only for Dexie Cloud but there's no dexie-cloud-addon active in given db."); if (!('permissions' in db.cloud)) throw new Error("usePermissions() requires a newer version of dexie-cloud-addon. Please upgrade it."); return useObservable( // @ts-ignore function () { return db.cloud.permissions(obj, table); }, [obj.realmId, obj.owner, table]); } exports.useLiveQuery = useLiveQuery; exports.useObservable = useObservable; exports.usePermissions = usePermissions; Object.defineProperty(exports, '__esModule', { value: true }); })); //# sourceMappingURL=dexie-react-hooks.js.map