UNPKG

@easy-peasy/react

Version:
222 lines (190 loc) 7.23 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var immerPeasy = require('immer-peasy'); var React = require('react'); var React__default = _interopDefault(React); var core = require('@easy-peasy/core'); var StoreContext = React.createContext(); // To get around it, we can conditionally useEffect on the server (no-op) and // useLayoutEffect in the browser. We need useLayoutEffect to ensure the store // subscription callback always has the selector from the latest render commit // available, otherwise a store update may happen between render and the effect, // which may cause missed updates; we also must ensure the store subscription // is created synchronously, otherwise a store update may occur before the // subscription is created and an inconsistent state may be observed var useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect; function createStoreStateHook(Context) { return function useStoreState(mapState) { var store = React.useContext(Context); var mapStateRef = React.useRef(mapState); var stateRef = React.useRef(); var mountedRef = React.useRef(true); var subscriptionMapStateError = React.useRef(); var _useReducer = React.useReducer(function (s) { return s + 1; }, 0), forceRender = _useReducer[1]; if (subscriptionMapStateError.current || mapStateRef.current !== mapState || stateRef.current === undefined) { try { stateRef.current = mapState(store.getState()); } catch (err) { if (process.env.NODE_ENV === 'development') { var errorMessage = "An error occurred trying to map state in a useStoreState hook: " + err.message + "."; if (subscriptionMapStateError.current) { errorMessage += "\nThis error may be related to the following error:\n" + subscriptionMapStateError.current.stack + "\n\nOriginal stack trace:"; } throw new Error(errorMessage); } throw subscriptionMapStateError.current || err; } } useIsomorphicLayoutEffect(function () { mapStateRef.current = mapState; subscriptionMapStateError.current = undefined; }); useIsomorphicLayoutEffect(function () { var checkMapState = function checkMapState() { try { var newState = mapStateRef.current(store.getState()); if (newState === stateRef.current) { return; } stateRef.current = newState; } catch (err) { // see https://github.com/reduxjs/react-redux/issues/1179 // There is a possibility mapState will fail due to stale state or // props, therefore we will just track the error and force our // component to update. It should then receive the updated state subscriptionMapStateError.current = err; } if (mountedRef.current) { forceRender({}); } }; var unsubscribe = store.subscribe(checkMapState); checkMapState(); return function () { mountedRef.current = false; unsubscribe(); }; }, []); return stateRef.current; }; } var useStoreState = createStoreStateHook(StoreContext); function createStoreActionsHook(Context) { return function useStoreActions(mapActions) { var store = React.useContext(Context); return mapActions(store.getActions()); }; } var useStoreActions = createStoreActionsHook(StoreContext); function createStoreDispatchHook(Context) { return function useStoreDispatch() { var store = React.useContext(Context); return store.dispatch; }; } var useStoreDispatch = createStoreDispatchHook(StoreContext); function useStore() { return React.useContext(StoreContext); } function createStoreRehydratedHook(Context) { return function useStoreRehydrated() { var store = React.useContext(Context); var _useState = React.useState(false), rehydrated = _useState[0], setRehydrated = _useState[1]; React.useEffect(function () { store.persist.resolveRehydration().then(function () { return setRehydrated(true); }); }, []); return rehydrated; }; } var useStoreRehydrated = createStoreRehydratedHook(StoreContext); function createTypedHooks() { return { useStoreActions: useStoreActions, useStoreDispatch: useStoreDispatch, useStoreState: useStoreState, useStoreRehydrated: useStoreRehydrated, useStore: useStore }; } /* eslint-disable react/prop-types */ function createContextStore(model, config) { var StoreContext = React.createContext(); function Provider(_ref) { var children = _ref.children, initialData = _ref.initialData; var store = React.useMemo(function () { return core.createStore(typeof model === 'function' ? model(initialData) : model, config); }, []); return React__default.createElement(StoreContext.Provider, { value: store }, children); } function useStore() { return React.useContext(StoreContext); } return { Provider: Provider, useStore: useStore, useStoreState: createStoreStateHook(StoreContext), useStoreActions: createStoreActionsHook(StoreContext), useStoreDispatch: createStoreDispatchHook(StoreContext), useStoreRehydrated: createStoreRehydratedHook(StoreContext) }; } /** * Some good references on the topic of reinitialisation: * - https://github.com/facebook/react/issues/14830 */ function createComponentStore(model, config) { return function useLocalStore(initialData) { var store = React.useMemo(function () { return core.createStore(typeof model === 'function' ? model(initialData) : model, config); }, []); var previousStateRef = React.useRef(store.getState()); var _useState = React.useState(function () { return store.getState(); }), currentState = _useState[0], setCurrentState = _useState[1]; React.useEffect(function () { return store.subscribe(function () { var nextState = store.getState(); if (previousStateRef.current !== nextState) { previousStateRef.current = nextState; setCurrentState(nextState); } }); }, [store]); return [currentState, store.getActions()]; }; } function StoreProvider(_ref) { var children = _ref.children, store = _ref.store; return React__default.createElement(StoreContext.Provider, { value: store }, children); } /** * The auto freeze feature of immer doesn't seem to work in our testing. We have * explicitly disabled it to avoid perf issues. */ immerPeasy.setAutoFreeze(false); exports.StoreProvider = StoreProvider; exports.createComponentStore = createComponentStore; exports.createContextStore = createContextStore; exports.createTypedHooks = createTypedHooks; exports.useStore = useStore; exports.useStoreActions = useStoreActions; exports.useStoreDispatch = useStoreDispatch; exports.useStoreRehydrated = useStoreRehydrated; exports.useStoreState = useStoreState; //# sourceMappingURL=easy-peasy-react.cjs.js.map