UNPKG

@anew/hooks

Version:

AnewJS React Hooks

266 lines (218 loc) 7.06 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) : typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) : (global = global || self, factory(global.Redux = {}, global.react)); }(this, (function (exports, react) { 'use strict'; function is(x, y) { if (x === y) { return x !== 0 || y !== 0 || 1 / x === 1 / y; } else { return x !== x && y !== y; } } function shallowEqual(objA, objB) { if (is(objA, objB)) return true; if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { return false; } var keysA = Object.keys(objA); var keysB = Object.keys(objB); if (keysA.length !== keysB.length) return false; for (var i = 0; i < keysA.length; i++) { if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { return false; } } return true; } // Default to a dummy "batch" implementation that just runs the callback var defaultNoopBatch = function defaultNoopBatch(callback) { callback(); }; var batch = defaultNoopBatch; // Allow injecting another batching function later var getBatch = function getBatch() { return batch; }; var nullListeners = { notify: function notify() {} }; function createListenerCollection() { var batch = getBatch(); var first = null; var last = null; return { clear: function clear() { first = null; last = null; }, notify: function notify() { batch(function () { var listener = first; while (listener) { listener.callback(); listener = listener.next; } }); }, get: function get() { var listeners = []; var listener = first; while (listener) { listeners.push(listener); listener = listener.next; } return listeners; }, subscribe: function subscribe(callback) { var isSubscribed = true; var listener = last = { callback: callback, next: null, prev: last }; if (listener.prev) { listener.prev.next = listener; } else { first = listener; } return function unsubscribe() { if (!isSubscribed || first === null) return; isSubscribed = false; if (listener.next) { listener.next.prev = listener.prev; } else { last = listener.prev; } if (listener.prev) { listener.prev.next = listener.next; } else { first = listener.next; } }; } }; } var Subscription = /*#__PURE__*/function () { function Subscription(store) { var _this = this; this.store = store; this.unsubscribe = null; this.listeners = nullListeners; this.handleChangeWrapper = function () { if (_this.onStateChange) { _this.onStateChange(); } }; } var _proto = Subscription.prototype; _proto.notifyNestedSubs = function notifyNestedSubs() { this.listeners.notify(); }; _proto.isSubscribed = function isSubscribed() { return Boolean(this.unsubscribe); }; _proto.trySubscribe = function trySubscribe() { if (!this.unsubscribe) { this.unsubscribe = this.store.subscribe(this.handleChangeWrapper); this.listeners = createListenerCollection(); } }; _proto.tryUnsubscribe = function tryUnsubscribe() { if (this.unsubscribe) { this.unsubscribe(); this.unsubscribe = null; if (this.listeners && this.listeners.clear) this.listeners.clear(); this.listeners = nullListeners; } }; return Subscription; }(); var refEquality = function refEquality(a, b) { return a === b; }; var useIsomorphicLayoutEffect = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined' ? react.useLayoutEffect : react.useEffect; function useStoreStateWithStoreAndSubscription(store, selector, equalityFn) { var _useReducer = react.useReducer(function (s) { return s + 1; }, 0), forceRender = _useReducer[1]; var subscription = react.useMemo(function () { return new Subscription(store); }, [store]); var latestSubscriptionCallbackError = react.useRef(); var latestSelector = react.useRef(); var latestStoreState = react.useRef(); var latestSelectedState = react.useRef(); var storeState = store.state; var selectedState; try { if (selector !== latestSelector.current || storeState !== latestStoreState.current || latestSubscriptionCallbackError.current) { selectedState = selector(storeState); } else { selectedState = latestSelectedState.current; } } catch (err) { if (latestSubscriptionCallbackError.current) { err.message += "\nThe error may be correlated with this previous error:\n" + latestSubscriptionCallbackError.current.stack + "\n\n"; } throw err; } useIsomorphicLayoutEffect(function () { latestSelector.current = selector; latestStoreState.current = storeState; latestSelectedState.current = selectedState; latestSubscriptionCallbackError.current = undefined; }); useIsomorphicLayoutEffect(function () { function checkForUpdates() { try { var newSelectedState = latestSelector.current(store.state); if (equalityFn(newSelectedState, latestSelectedState.current)) { return; } latestSelectedState.current = newSelectedState; } catch (err) { // we ignore all errors here, since when the component // is re-rendered, the selectors are called again, and // will throw again, if neither props nor store state // changed latestSubscriptionCallbackError.current = err; } forceRender(); } subscription.onStateChange = checkForUpdates; subscription.trySubscribe(); checkForUpdates(); return function () { return subscription.tryUnsubscribe(); }; }, [store, subscription]); return selectedState; } /** * Hook factory, which creates a `useStoreState` hook bound to a given store. * * @param {Store} [store] Store * @returns {Function} A `useStoreState` hook bound to the specified store. */ function createUseStoreState(store) { function useStoreState(selector, equalityFn) { if (equalityFn === void 0) { equalityFn = refEquality; } if ( !selector) { throw new Error("You must pass a selector to useStoreState"); } var selectedState = useStoreStateWithStoreAndSubscription(store, selector, equalityFn); react.useDebugValue(selectedState); return selectedState; } useStoreState.withSallowEqual = function useStoreStateWithShallowEqual(selector) { return useStoreState(selector, shallowEqual); }; return useStoreState; } exports.createUseStoreState = createUseStoreState; exports.shallowEqual = shallowEqual; Object.defineProperty(exports, '__esModule', { value: true }); })));