UNPKG

overmind-react

Version:
133 lines 4.74 kB
import * as React from 'react'; import { ENVIRONMENT, EventType, MODE_SSR, } from 'overmind'; const IS_PRODUCTION = ENVIRONMENT === 'production'; const IS_TEST = ENVIRONMENT === 'test'; const isNode = !IS_TEST && typeof process !== 'undefined' && process.title && process.title.includes('node'); function getFiberType(component) { if (component.type) { // React.memo return getFiberType(component.type); } // React.forwardRef return component.render || component; } // Inspired from https://github.com/facebook/react/blob/master/packages/react-devtools-shared/src/backend/renderer.js function getDisplayName(component) { const type = getFiberType(component); return type.displayName || type.name || 'Anonymous'; } function throwMissingContextError() { throw new Error('The Overmind hook could not find an Overmind instance on the context of React. Please make sure you use the Provider component at the top of your application and expose the Overmind instance there. Please read more in the React guide on the website'); } const context = React.createContext({}); let nextComponentId = 0; export const Provider = context.Provider; function useForceRerender() { const [flushId, forceRerender] = React.useState(-1); return { flushId, forceRerender, }; } let currentComponentInstanceId = 0; const { __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: oldReactInternals, __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE: newReactInternals, } = React; const useCurrentComponent = () => { return (oldReactInternals?.ReactCurrentOwner?.current?.elementType ?? newReactInternals?.A?.getOwner?.()?.elementType ?? {}); }; const useState = (cb) => { const overmind = React.useContext(context); if (!overmind.mode) { throwMissingContextError(); } if (isNode || overmind.mode.mode === MODE_SSR) { return overmind.state; } const { forceRerender } = useForceRerender(); const trackStateTree = overmind.proxyStateTreeInstance.getTrackStateTree(); const state = cb ? cb(trackStateTree.state) : trackStateTree.state; trackStateTree.track(); if (IS_PRODUCTION) { React.useEffect(() => trackStateTree.subscribe((_, __, flushId) => { forceRerender(flushId); }), [trackStateTree]); } else { const component = useCurrentComponent(); const name = getDisplayName(component); component.__componentId = typeof component.__componentId === 'undefined' ? nextComponentId++ : component.__componentId; const { current: componentInstanceId } = React.useRef(currentComponentInstanceId++); React.useEffect(() => { overmind.eventHub.emitAsync(EventType.COMPONENT_ADD, { componentId: component.__componentId, componentInstanceId, name, paths: [], }); return () => { overmind.eventHub.emitAsync(EventType.COMPONENT_REMOVE, { componentId: component.__componentId, componentInstanceId, name, }); }; }, []); React.useEffect(() => { const dispose = trackStateTree.subscribe((_, __, flushId) => { overmind.eventHub.emitAsync(EventType.COMPONENT_UPDATE, { componentId: component.__componentId, componentInstanceId, name, paths: Array.from(trackStateTree.pathDependencies), flushId, }); forceRerender(flushId); }); return () => { dispose(); }; }, [trackStateTree]); } return state; }; const useActions = () => { const overmind = React.useContext(context); if (!overmind.mode) { throwMissingContextError(); } return overmind.actions; }; const useEffects = () => { const overmind = React.useContext(context); if (!overmind.mode) { throwMissingContextError(); } return overmind.effects; }; const useReaction = () => { const overmind = React.useContext(context); if (!overmind.mode) { throwMissingContextError(); } return overmind.reaction; }; export const createStateHook = () => // eslint-disable-next-line dot-notation useState; export const createActionsHook = () => { return useActions; }; export const createEffectsHook = () => { return useEffects; }; export const createReactionHook = () => { return useReaction; }; //# sourceMappingURL=index.js.map