UNPKG

fluidstate-react

Version:

Library for using fine-grained reactivity state management library fluidstate in React

170 lines (157 loc) 6.53 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createReactiveSetup = void 0; var _react = require("react"); var _hoc = require("./hoc"); var _hooks = require("./hooks"); var _onceRef = require("./once-ref"); var _jsxRuntime = require("react/jsx-runtime"); /** * A phantom symbol used to associate a `State` type with a component type. * This enables utility types like `StateType` to extract the state type * from the component type itself, a technique similar to nominal typing. */ /** * A React Provider component for providing mock state, typically used in tests * or Storybook. It provides a partial state object via its `value` prop to its children. * @template State The full state type. */ /** * The core type definition for the ReactiveProvider component. * @private */ /** * A React Provider component that creates and provides reactive state to its children. * It ensures that the state is created only once per component instance and automatically * manages the lifecycle of any reactions defined in the state. * * It also carries a phantom `State` type, allowing utility types to infer the state shape. * * @template SetupProps The type of props required to initialize the state. * @template State The type of the reactive state object. */ /** * A hook for consuming reactive state within a component. * It subscribes to changes in the slice of state returned by `readReactiveState` * and re-renders the component when that data changes. * * @template State The type of the global reactive state. * @param readReactiveState A function that selects a part of the state to subscribe to. * @returns The value returned by `readReactiveState`. */ /** * A higher-order component (HOC) that injects reactive state into a component as a `state` prop. * The wrapped component will automatically re-render when the reactive state it uses changes. * * @template State The type of the global reactive state. * @param component The component to wrap. * @returns A new component that receives the reactive state. */ /** * A factory function type for creating the reactive state. * It receives `setupProps` and is expected to return the initial state object. * * @template SetupProps The type of props for state initialization. * @template State The type of the reactive state object. */ /** * A utility type that extracts the `State` type from a `ReactiveProvider` type. * @template T The `ReactiveProvider` type. */ /** * A utility type that extracts the `SetupProps` type from a `ReactiveProvider` type. * @template T The `ReactiveProvider` type. */ /** * A utility type that extracts the `CreateState` function type from a `ReactiveProvider` type. * @template T The `ReactiveProvider` type. */ /** * An object containing the complete set of utilities for a specific reactive state setup. * This includes the provider, consumer hook, HOC, mock provider, and state factory. */ /** * Creates a cohesive set of tools for managing a specific piece of reactive state * within a React application. This pattern promotes encapsulation and simplifies * state management by providing a dedicated Provider, consumer hook, and HOC. * * The created state is instantiated once per `ReactiveProvider` and is automatically * cleaned up, including any associated reactions, when the provider unmounts. * * @template SetupProps The type of props needed by the `createState` function. * If no props are needed, this can be `undefined`. * @template State The shape of the reactive state object. If the state object contains * a `reactions` property (an array of `Reaction` instances), they will be automatically * cleaned up when the provider unmounts. * @param {CreateState<SetupProps, State>} createState A factory function that initializes * and returns the reactive state. It is called once when the `ReactiveProvider` mounts. * @returns {ReactiveSetup<SetupProps, State>} An object containing the setup utilities. */ const createReactiveSetup = createState => { const StateContext = /*#__PURE__*/(0, _react.createContext)(null); const ReactiveProviderCore = props => { const state = (0, _onceRef.useOnceRef)(() => createState(props.setupProps)); (0, _react.useEffect)(() => { return () => { stopReactions(state.current); }; }, []); return /*#__PURE__*/(0, _jsxRuntime.jsx)(StateContext.Provider, { value: state.current, children: props.children }); }; const ReactiveProvider = ReactiveProviderCore; const useReactiveState = readReactiveState => { const state = (0, _react.useContext)(StateContext); if (state == null) { throw new Error("useReactiveState must be used within a ReactiveProvider"); } return (0, _hooks.useReactive)(() => readReactiveState(state), [readReactiveState]); }; const withReactiveState = component => { const ReactiveComponent = (0, _hoc.withReactive)(component); const WithStateComponent = props => { const state = (0, _react.useContext)(StateContext); if (state == null) { throw new Error("withReactiveState must be used within a ReactiveProvider"); } return /*#__PURE__*/(0, _jsxRuntime.jsx)(ReactiveComponent, { ...props, state: state }); }; if (component.displayName || component.name) { WithStateComponent.displayName = `withReactiveState(${component.displayName || component.name})`; } return WithStateComponent; }; const MockProvider = StateContext.Provider; return { ReactiveProvider, useReactiveState, withReactiveState, MockProvider, createState, StateContext: StateContext }; }; /** * Stops reactions provided by a state. Reactions are optional, and the convention is that, if the reactions * are provided in an array in the "reactions" property of the returned state, they will be automatically * cleaned up when the provided component unmounts. */ exports.createReactiveSetup = createReactiveSetup; const stopReactions = currentState => { if (currentState && typeof currentState === "object" && "reactions" in currentState && Array.isArray(currentState.reactions)) { for (const currentReaction of currentState.reactions) { let reaction = currentReaction; if (reaction && typeof reaction === "object" && "stop" in reaction && typeof reaction.stop === "function") { reaction.stop(); } } } }; //# sourceMappingURL=reactive-setup.js.map