UNPKG

react-redux

Version:

Official React bindings for Redux

1,012 lines (1,011 loc) • 39.9 kB
import * as React from "react"; import { useSyncExternalStoreWithSelector } from "use-sync-external-store/with-selector.js"; //#region src/utils/react-is.ts const IS_REACT_19 = /* @__PURE__ */ React.version.startsWith("19"); const REACT_ELEMENT_TYPE = /* @__PURE__ */ Symbol.for(IS_REACT_19 ? "react.transitional.element" : "react.element"); const REACT_PORTAL_TYPE = /* @__PURE__ */ Symbol.for("react.portal"); const REACT_FRAGMENT_TYPE = /* @__PURE__ */ Symbol.for("react.fragment"); const REACT_STRICT_MODE_TYPE = /* @__PURE__ */ Symbol.for("react.strict_mode"); const REACT_PROFILER_TYPE = /* @__PURE__ */ Symbol.for("react.profiler"); const REACT_CONSUMER_TYPE = /* @__PURE__ */ Symbol.for("react.consumer"); const REACT_CONTEXT_TYPE = /* @__PURE__ */ Symbol.for("react.context"); const REACT_FORWARD_REF_TYPE = /* @__PURE__ */ Symbol.for("react.forward_ref"); const REACT_SUSPENSE_TYPE = /* @__PURE__ */ Symbol.for("react.suspense"); const REACT_SUSPENSE_LIST_TYPE = /* @__PURE__ */ Symbol.for("react.suspense_list"); const REACT_MEMO_TYPE = /* @__PURE__ */ Symbol.for("react.memo"); const REACT_LAZY_TYPE = /* @__PURE__ */ Symbol.for("react.lazy"); const REACT_OFFSCREEN_TYPE = /* @__PURE__ */ Symbol.for("react.offscreen"); const REACT_CLIENT_REFERENCE = /* @__PURE__ */ Symbol.for("react.client.reference"); const ForwardRef = REACT_FORWARD_REF_TYPE; const Memo = REACT_MEMO_TYPE; function isValidElementType(type) { return typeof type === "string" || typeof type === "function" || type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || type === REACT_OFFSCREEN_TYPE || typeof type === "object" && type !== null && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_CONSUMER_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_CLIENT_REFERENCE || type.getModuleId !== void 0) ? !0 : !1; } function typeOf(object) { if (typeof object === "object" && object !== null) { const { $$typeof } = object; switch ($$typeof) { case REACT_ELEMENT_TYPE: switch (object = object.type, object) { case REACT_FRAGMENT_TYPE: case REACT_PROFILER_TYPE: case REACT_STRICT_MODE_TYPE: case REACT_SUSPENSE_TYPE: case REACT_SUSPENSE_LIST_TYPE: return object; default: switch (object = object && object.$$typeof, object) { case REACT_CONTEXT_TYPE: case REACT_FORWARD_REF_TYPE: case REACT_LAZY_TYPE: case REACT_MEMO_TYPE: return object; case REACT_CONSUMER_TYPE: return object; default: return $$typeof; } } case REACT_PORTAL_TYPE: return $$typeof; } } } function isContextConsumer(object) { return IS_REACT_19 ? typeOf(object) === REACT_CONSUMER_TYPE : typeOf(object) === REACT_CONTEXT_TYPE; } function isMemo(object) { return typeOf(object) === REACT_MEMO_TYPE; } //#endregion //#region src/utils/warning.ts /** * Prints a warning in the console if it exists. * * @param {String} message The warning message. * @returns {void} */ function warning(message) { if (typeof console !== "undefined" && typeof console.error === "function") console.error(message); try { throw new Error(message); } catch (e) {} } //#endregion //#region src/connect/verifySubselectors.ts function verify(selector, methodName) { if (!selector) throw new Error(`Unexpected value for ${methodName} in connect.`); else if (methodName === "mapStateToProps" || methodName === "mapDispatchToProps") { if (!Object.prototype.hasOwnProperty.call(selector, "dependsOnOwnProps")) warning(`The selector for ${methodName} of connect did not specify a value for dependsOnOwnProps.`); } } function verifySubselectors(mapStateToProps, mapDispatchToProps, mergeProps) { verify(mapStateToProps, "mapStateToProps"); verify(mapDispatchToProps, "mapDispatchToProps"); verify(mergeProps, "mergeProps"); } //#endregion //#region src/connect/selectorFactory.ts function pureFinalPropsSelectorFactory(mapStateToProps, mapDispatchToProps, mergeProps, dispatch, { areStatesEqual, areOwnPropsEqual, areStatePropsEqual }) { let hasRunAtLeastOnce = false; let state; let ownProps; let stateProps; let dispatchProps; let mergedProps; function handleFirstCall(firstState, firstOwnProps) { state = firstState; ownProps = firstOwnProps; stateProps = mapStateToProps(state, ownProps); dispatchProps = mapDispatchToProps(dispatch, ownProps); mergedProps = mergeProps(stateProps, dispatchProps, ownProps); hasRunAtLeastOnce = true; return mergedProps; } function handleNewPropsAndNewState() { stateProps = mapStateToProps(state, ownProps); if (mapDispatchToProps.dependsOnOwnProps) dispatchProps = mapDispatchToProps(dispatch, ownProps); mergedProps = mergeProps(stateProps, dispatchProps, ownProps); return mergedProps; } function handleNewProps() { if (mapStateToProps.dependsOnOwnProps) stateProps = mapStateToProps(state, ownProps); if (mapDispatchToProps.dependsOnOwnProps) dispatchProps = mapDispatchToProps(dispatch, ownProps); mergedProps = mergeProps(stateProps, dispatchProps, ownProps); return mergedProps; } function handleNewState() { const nextStateProps = mapStateToProps(state, ownProps); const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps); stateProps = nextStateProps; if (statePropsChanged) mergedProps = mergeProps(stateProps, dispatchProps, ownProps); return mergedProps; } function handleSubsequentCalls(nextState, nextOwnProps) { const propsChanged = !areOwnPropsEqual(nextOwnProps, ownProps); const stateChanged = !areStatesEqual(nextState, state, nextOwnProps, ownProps); state = nextState; ownProps = nextOwnProps; if (propsChanged && stateChanged) return handleNewPropsAndNewState(); if (propsChanged) return handleNewProps(); if (stateChanged) return handleNewState(); return mergedProps; } return function pureFinalPropsSelector(nextState, nextOwnProps) { return hasRunAtLeastOnce ? handleSubsequentCalls(nextState, nextOwnProps) : handleFirstCall(nextState, nextOwnProps); }; } function finalPropsSelectorFactory(dispatch, { initMapStateToProps, initMapDispatchToProps, initMergeProps, ...options }) { const mapStateToProps = initMapStateToProps(dispatch, options); const mapDispatchToProps = initMapDispatchToProps(dispatch, options); const mergeProps = initMergeProps(dispatch, options); if (process.env.NODE_ENV !== "production") verifySubselectors(mapStateToProps, mapDispatchToProps, mergeProps); return pureFinalPropsSelectorFactory(mapStateToProps, mapDispatchToProps, mergeProps, dispatch, options); } //#endregion //#region src/utils/bindActionCreators.ts function bindActionCreators(actionCreators, dispatch) { const boundActionCreators = {}; for (const key in actionCreators) { const actionCreator = actionCreators[key]; if (typeof actionCreator === "function") boundActionCreators[key] = (...args) => dispatch(actionCreator(...args)); } return boundActionCreators; } //#endregion //#region src/utils/isPlainObject.ts /** * @param {any} obj The object to inspect. * @returns {boolean} True if the argument appears to be a plain object. */ function isPlainObject(obj) { if (typeof obj !== "object" || obj === null) return false; const proto = Object.getPrototypeOf(obj); if (proto === null) return true; let baseProto = proto; while (Object.getPrototypeOf(baseProto) !== null) baseProto = Object.getPrototypeOf(baseProto); return proto === baseProto; } //#endregion //#region src/utils/verifyPlainObject.ts function verifyPlainObject(value, displayName, methodName) { if (!isPlainObject(value)) warning(`${methodName}() in ${displayName} must return a plain object. Instead received ${value}.`); } //#endregion //#region src/connect/wrapMapToProps.ts function wrapMapToPropsConstant(getConstant) { return function initConstantSelector(dispatch) { const constant = getConstant(dispatch); function constantSelector() { return constant; } constantSelector.dependsOnOwnProps = false; return constantSelector; }; } function getDependsOnOwnProps(mapToProps) { return mapToProps.dependsOnOwnProps != null ? Boolean(mapToProps.dependsOnOwnProps) : mapToProps.length !== 1; } function wrapMapToPropsFunc(mapToProps, methodName) { return function initProxySelector(dispatch, { displayName }) { const proxy = function mapToPropsProxy(stateOrDispatch, ownProps) { return proxy.dependsOnOwnProps ? proxy.mapToProps(stateOrDispatch, ownProps) : proxy.mapToProps(stateOrDispatch, void 0); }; proxy.dependsOnOwnProps = true; proxy.mapToProps = function detectFactoryAndVerify(stateOrDispatch, ownProps) { proxy.mapToProps = mapToProps; proxy.dependsOnOwnProps = getDependsOnOwnProps(mapToProps); let props = proxy(stateOrDispatch, ownProps); if (typeof props === "function") { proxy.mapToProps = props; proxy.dependsOnOwnProps = getDependsOnOwnProps(props); props = proxy(stateOrDispatch, ownProps); } if (process.env.NODE_ENV !== "production") verifyPlainObject(props, displayName, methodName); return props; }; return proxy; }; } //#endregion //#region src/connect/invalidArgFactory.ts function createInvalidArgFactory(arg, name) { return (dispatch, options) => { throw new Error(`Invalid value of type ${typeof arg} for ${name} argument when connecting component ${options.wrappedComponentName}.`); }; } //#endregion //#region src/connect/mapDispatchToProps.ts function mapDispatchToPropsFactory(mapDispatchToProps) { return mapDispatchToProps && typeof mapDispatchToProps === "object" ? wrapMapToPropsConstant((dispatch) => bindActionCreators(mapDispatchToProps, dispatch)) : !mapDispatchToProps ? wrapMapToPropsConstant((dispatch) => ({ dispatch })) : typeof mapDispatchToProps === "function" ? wrapMapToPropsFunc(mapDispatchToProps, "mapDispatchToProps") : createInvalidArgFactory(mapDispatchToProps, "mapDispatchToProps"); } //#endregion //#region src/connect/mapStateToProps.ts function mapStateToPropsFactory(mapStateToProps) { return !mapStateToProps ? wrapMapToPropsConstant(() => ({})) : typeof mapStateToProps === "function" ? wrapMapToPropsFunc(mapStateToProps, "mapStateToProps") : createInvalidArgFactory(mapStateToProps, "mapStateToProps"); } //#endregion //#region src/connect/mergeProps.ts function defaultMergeProps(stateProps, dispatchProps, ownProps) { return { ...ownProps, ...stateProps, ...dispatchProps }; } function wrapMergePropsFunc(mergeProps) { return function initMergePropsProxy(dispatch, { displayName, areMergedPropsEqual }) { let hasRunOnce = false; let mergedProps; return function mergePropsProxy(stateProps, dispatchProps, ownProps) { const nextMergedProps = mergeProps(stateProps, dispatchProps, ownProps); if (hasRunOnce) { if (!areMergedPropsEqual(nextMergedProps, mergedProps)) mergedProps = nextMergedProps; } else { hasRunOnce = true; mergedProps = nextMergedProps; if (process.env.NODE_ENV !== "production") verifyPlainObject(mergedProps, displayName, "mergeProps"); } return mergedProps; }; }; } function mergePropsFactory(mergeProps) { return !mergeProps ? () => defaultMergeProps : typeof mergeProps === "function" ? wrapMergePropsFunc(mergeProps) : createInvalidArgFactory(mergeProps, "mergeProps"); } //#endregion //#region src/utils/batch.ts function defaultNoopBatch(callback) { callback(); } //#endregion //#region src/utils/Subscription.ts function createListenerCollection() { let first = null; let last = null; return { clear() { first = null; last = null; }, notify() { defaultNoopBatch(() => { let listener = first; while (listener) { listener.callback(); listener = listener.next; } }); }, get() { const listeners = []; let listener = first; while (listener) { listeners.push(listener); listener = listener.next; } return listeners; }, subscribe(callback) { let isSubscribed = true; const listener = last = { 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; }; } }; } const nullListeners = { notify() {}, get: () => [] }; function createSubscription(store, parentSub) { let unsubscribe; let listeners = nullListeners; let subscriptionsAmount = 0; let selfSubscribed = false; function addNestedSub(listener) { trySubscribe(); const cleanupListener = listeners.subscribe(listener); let removed = false; return () => { if (!removed) { removed = true; cleanupListener(); tryUnsubscribe(); } }; } function notifyNestedSubs() { listeners.notify(); } function handleChangeWrapper() { if (subscription.onStateChange) subscription.onStateChange(); } function isSubscribed() { return selfSubscribed; } function trySubscribe() { subscriptionsAmount++; if (!unsubscribe) { unsubscribe = parentSub ? parentSub.addNestedSub(handleChangeWrapper) : store.subscribe(handleChangeWrapper); listeners = createListenerCollection(); } } function tryUnsubscribe() { subscriptionsAmount--; if (unsubscribe && subscriptionsAmount === 0) { unsubscribe(); unsubscribe = void 0; listeners.clear(); listeners = nullListeners; } } function trySubscribeSelf() { if (!selfSubscribed) { selfSubscribed = true; trySubscribe(); } } function tryUnsubscribeSelf() { if (selfSubscribed) { selfSubscribed = false; tryUnsubscribe(); } } const subscription = { addNestedSub, notifyNestedSubs, handleChangeWrapper, isSubscribed, trySubscribe: trySubscribeSelf, tryUnsubscribe: tryUnsubscribeSelf, getListeners: () => listeners }; return subscription; } //#endregion //#region src/utils/useIsomorphicLayoutEffect.ts const canUseDOM = () => !!(typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined"); const isDOM = /* @__PURE__ */ canUseDOM(); /** * Checks if the code is running in a React Native environment. * * @returns Whether the code is running in a React Native environment. * * @see {@link https://github.com/facebook/react-native/issues/1331 Reference} */ const isRunningInReactNative = () => typeof navigator !== "undefined" && navigator.product === "ReactNative"; const isReactNative = /* @__PURE__ */ isRunningInReactNative(); const getUseIsomorphicLayoutEffect = () => isDOM || isReactNative ? React.useLayoutEffect : React.useEffect; const useIsomorphicLayoutEffect = /* @__PURE__ */ getUseIsomorphicLayoutEffect(); //#endregion //#region src/utils/shallowEqual.ts 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; const keysA = Object.keys(objA); const keysB = Object.keys(objB); if (keysA.length !== keysB.length) return false; for (let 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; } //#endregion //#region src/utils/hoistStatics.ts const REACT_STATICS = { childContextTypes: true, contextType: true, contextTypes: true, defaultProps: true, displayName: true, getDefaultProps: true, getDerivedStateFromError: true, getDerivedStateFromProps: true, mixins: true, propTypes: true, type: true }; const KNOWN_STATICS = { name: true, length: true, prototype: true, caller: true, callee: true, arguments: true, arity: true }; const FORWARD_REF_STATICS = { $$typeof: true, render: true, defaultProps: true, displayName: true, propTypes: true }; const MEMO_STATICS = { $$typeof: true, compare: true, defaultProps: true, displayName: true, propTypes: true, type: true }; const TYPE_STATICS = { [ForwardRef]: FORWARD_REF_STATICS, [Memo]: MEMO_STATICS }; function getStatics(component) { if (isMemo(component)) return MEMO_STATICS; return TYPE_STATICS[component["$$typeof"]] || REACT_STATICS; } const defineProperty = Object.defineProperty; const getOwnPropertyNames = Object.getOwnPropertyNames; const getOwnPropertySymbols = Object.getOwnPropertySymbols; const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; const getPrototypeOf = Object.getPrototypeOf; const objectPrototype = Object.prototype; function hoistNonReactStatics(targetComponent, sourceComponent) { if (typeof sourceComponent !== "string") { if (objectPrototype) { const inheritedComponent = getPrototypeOf(sourceComponent); if (inheritedComponent && inheritedComponent !== objectPrototype) hoistNonReactStatics(targetComponent, inheritedComponent); } let keys = getOwnPropertyNames(sourceComponent); if (getOwnPropertySymbols) keys = keys.concat(getOwnPropertySymbols(sourceComponent)); const targetStatics = getStatics(targetComponent); const sourceStatics = getStatics(sourceComponent); for (let i = 0; i < keys.length; ++i) { const key = keys[i]; if (!KNOWN_STATICS[key] && !(sourceStatics && sourceStatics[key]) && !(targetStatics && targetStatics[key])) { const descriptor = getOwnPropertyDescriptor(sourceComponent, key); try { defineProperty(targetComponent, key, descriptor); } catch (e) {} } } } return targetComponent; } //#endregion //#region src/components/Context.ts const ContextKey = /* @__PURE__ */ Symbol.for(`react-redux-context`); const gT = typeof globalThis !== "undefined" ? globalThis : {}; function getContext() { if (!React.createContext) return {}; const contextMap = gT[ContextKey] ??= /* @__PURE__ */ new Map(); let realContext = contextMap.get(React.createContext); if (!realContext) { realContext = React.createContext(null); if (process.env.NODE_ENV !== "production") realContext.displayName = "ReactRedux"; contextMap.set(React.createContext, realContext); } return realContext; } const ReactReduxContext = /*#__PURE__*/ getContext(); //#endregion //#region src/components/connect.tsx const NO_SUBSCRIPTION_ARRAY = [null, null]; const stringifyComponent = (Comp) => { try { return JSON.stringify(Comp); } catch (err) { return String(Comp); } }; function useIsomorphicLayoutEffectWithArgs(effectFunc, effectArgs, dependencies) { useIsomorphicLayoutEffect(() => effectFunc(...effectArgs), dependencies); } function captureWrapperProps(lastWrapperProps, lastChildProps, renderIsScheduled, wrapperProps, childPropsFromStoreUpdate, notifyNestedSubs) { lastWrapperProps.current = wrapperProps; renderIsScheduled.current = false; if (childPropsFromStoreUpdate.current) { childPropsFromStoreUpdate.current = null; notifyNestedSubs(); } } function subscribeUpdates(shouldHandleStateChanges, store, subscription, childPropsSelector, lastWrapperProps, lastChildProps, renderIsScheduled, isMounted, childPropsFromStoreUpdate, notifyNestedSubs, additionalSubscribeListener, displayName) { if (!shouldHandleStateChanges) return () => {}; let didUnsubscribe = false; let lastThrownError = null; const checkForUpdates = () => { if (didUnsubscribe || !isMounted.current) return; const latestStoreState = store.getState(); let newChildProps, error; try { newChildProps = childPropsSelector(latestStoreState, lastWrapperProps.current); } catch (e) { error = e; lastThrownError = e; if (process.env.NODE_ENV !== "production") console.error(`An error occurred in \`mapStateToProps\` (or a selector) of the \`connect()\`-ed component "${displayName}". See https://github.com/reduxjs/react-redux/issues/1942 for details.`, e); } if (!error) lastThrownError = null; if (newChildProps === lastChildProps.current) { if (!renderIsScheduled.current) notifyNestedSubs(); } else { lastChildProps.current = newChildProps; childPropsFromStoreUpdate.current = newChildProps; renderIsScheduled.current = true; additionalSubscribeListener(); } }; subscription.onStateChange = checkForUpdates; subscription.trySubscribe(); checkForUpdates(); const unsubscribeWrapper = () => { didUnsubscribe = true; subscription.tryUnsubscribe(); subscription.onStateChange = null; if (lastThrownError) throw lastThrownError; }; return unsubscribeWrapper; } function strictEqual(a, b) { return a === b; } let hasWarnedAboutDeprecatedPureOption = false; /** * @deprecated * * **We recommend using the `useSelector` and `useDispatch` hooks instead.** * See https://react-redux.js.org/api/hooks * * If you need to use `connect` without this visual deprecation warning, * import `legacy_connect` instead: * * `import { legacy_connect as connect } from 'react-redux'` * * Connects a React component to a Redux store. * * - Without arguments, just wraps the component, without changing the behavior / props * * - If 2 params are passed (3rd param, mergeProps, is skipped), default behavior * is to override ownProps (as stated in the docs), so what remains is everything that's * not a state or dispatch prop * * - When 3rd param is passed, we don't know if ownProps propagate and whether they * should be valid component props, because it depends on mergeProps implementation. * As such, it is the user's responsibility to extend ownProps interface from state or * dispatch props or both when applicable * * @param mapStateToProps A function that extracts values from state * @param mapDispatchToProps Setup for dispatching actions * @param mergeProps Optional callback to merge state and dispatch props together * @param options Options for configuring the connection * */ function _connect(mapStateToProps, mapDispatchToProps, mergeProps, { pure, areStatesEqual = strictEqual, areOwnPropsEqual = shallowEqual, areStatePropsEqual = shallowEqual, areMergedPropsEqual = shallowEqual, forwardRef = false, context = ReactReduxContext } = {}) { if (process.env.NODE_ENV !== "production") { if (pure !== void 0 && !hasWarnedAboutDeprecatedPureOption) { hasWarnedAboutDeprecatedPureOption = true; warning("The `pure` option has been removed. `connect` is now always a \"pure/memoized\" component"); } } const Context = context; const initMapStateToProps = mapStateToPropsFactory(mapStateToProps); const initMapDispatchToProps = mapDispatchToPropsFactory(mapDispatchToProps); const initMergeProps = mergePropsFactory(mergeProps); const shouldHandleStateChanges = Boolean(mapStateToProps); const wrapWithConnect = (WrappedComponent) => { if (process.env.NODE_ENV !== "production") { if (!/* @__PURE__ */ isValidElementType(WrappedComponent)) throw new Error(`You must pass a component to the function returned by connect. Instead received ${stringifyComponent(WrappedComponent)}`); } const wrappedComponentName = WrappedComponent.displayName || WrappedComponent.name || "Component"; const displayName = `Connect(${wrappedComponentName})`; const selectorFactoryOptions = { shouldHandleStateChanges, displayName, wrappedComponentName, WrappedComponent, initMapStateToProps, initMapDispatchToProps, initMergeProps, areStatesEqual, areStatePropsEqual, areOwnPropsEqual, areMergedPropsEqual }; function ConnectFunction(props) { const [propsContext, reactReduxForwardedRef, wrapperProps] = React.useMemo(() => { const { reactReduxForwardedRef, ...wrapperProps } = props; return [ props.context, reactReduxForwardedRef, wrapperProps ]; }, [props]); const ContextToUse = React.useMemo(() => { let ResultContext = Context; if (propsContext?.Consumer) { if (process.env.NODE_ENV !== "production") { if (!/* @__PURE__ */ isContextConsumer(/* @__PURE__ */ React.createElement(propsContext.Consumer, null))) throw new Error("You must pass a valid React context consumer as `props.context`"); } ResultContext = propsContext; } return ResultContext; }, [propsContext, Context]); const contextValue = React.useContext(ContextToUse); const didStoreComeFromProps = Boolean(props.store) && Boolean(props.store.getState) && Boolean(props.store.dispatch); const didStoreComeFromContext = Boolean(contextValue) && Boolean(contextValue.store); if (process.env.NODE_ENV !== "production" && !didStoreComeFromProps && !didStoreComeFromContext) throw new Error(`Could not find "store" in the context of "${displayName}". Either wrap the root component in a <Provider>, or pass a custom React context provider to <Provider> and the corresponding React context consumer to ${displayName} in connect options.`); const store = didStoreComeFromProps ? props.store : contextValue.store; const getServerState = didStoreComeFromContext ? contextValue.getServerState : store.getState; const childPropsSelector = React.useMemo(() => { return finalPropsSelectorFactory(store.dispatch, selectorFactoryOptions); }, [store]); const [subscription, notifyNestedSubs] = React.useMemo(() => { if (!shouldHandleStateChanges) return NO_SUBSCRIPTION_ARRAY; const subscription = createSubscription(store, didStoreComeFromProps ? void 0 : contextValue.subscription); return [subscription, subscription.notifyNestedSubs.bind(subscription)]; }, [ store, didStoreComeFromProps, contextValue ]); const overriddenContextValue = React.useMemo(() => { if (didStoreComeFromProps) return contextValue; return { ...contextValue, subscription }; }, [ didStoreComeFromProps, contextValue, subscription ]); const lastChildProps = React.useRef(void 0); const lastWrapperProps = React.useRef(wrapperProps); const childPropsFromStoreUpdate = React.useRef(void 0); const renderIsScheduled = React.useRef(false); const isMounted = React.useRef(false); /** * @todo Change this to `React.useRef<Error>(undefined)` after upgrading to React 19. */ const latestSubscriptionCallbackError = React.useRef(void 0); useIsomorphicLayoutEffect(() => { isMounted.current = true; return () => { isMounted.current = false; }; }, []); const actualChildPropsSelector = React.useMemo(() => { const selector = () => { if (childPropsFromStoreUpdate.current && wrapperProps === lastWrapperProps.current) return childPropsFromStoreUpdate.current; return childPropsSelector(store.getState(), wrapperProps); }; return selector; }, [store, wrapperProps]); const subscribeForReact = React.useMemo(() => { const subscribe = (reactListener) => { if (!subscription) return () => {}; return subscribeUpdates(shouldHandleStateChanges, store, subscription, childPropsSelector, lastWrapperProps, lastChildProps, renderIsScheduled, isMounted, childPropsFromStoreUpdate, notifyNestedSubs, reactListener, displayName); }; return subscribe; }, [subscription]); useIsomorphicLayoutEffectWithArgs(captureWrapperProps, [ lastWrapperProps, lastChildProps, renderIsScheduled, wrapperProps, childPropsFromStoreUpdate, notifyNestedSubs ]); let actualChildProps; try { actualChildProps = React.useSyncExternalStore(subscribeForReact, actualChildPropsSelector, getServerState ? () => childPropsSelector(getServerState(), wrapperProps) : actualChildPropsSelector); } 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(() => { latestSubscriptionCallbackError.current = void 0; childPropsFromStoreUpdate.current = void 0; lastChildProps.current = actualChildProps; }); const renderedWrappedComponent = React.useMemo(() => { const effectiveProps = { ...actualChildProps }; if (forwardRef) effectiveProps.ref = reactReduxForwardedRef; return /* @__PURE__ */ React.createElement(WrappedComponent, effectiveProps); }, [ reactReduxForwardedRef, WrappedComponent, actualChildProps ]); return React.useMemo(() => { if (shouldHandleStateChanges) return /* @__PURE__ */ React.createElement(ContextToUse.Provider, { value: overriddenContextValue }, renderedWrappedComponent); return renderedWrappedComponent; }, [ ContextToUse, renderedWrappedComponent, overriddenContextValue ]); } const Connect = React.memo(ConnectFunction); Connect.WrappedComponent = WrappedComponent; Connect.displayName = ConnectFunction.displayName = displayName; if (forwardRef) { const forwarded = React.forwardRef(function forwardConnectRef(props, ref) { return /* @__PURE__ */ React.createElement(Connect, { ...props, reactReduxForwardedRef: ref }); }); forwarded.displayName = displayName; forwarded.WrappedComponent = WrappedComponent; return /*#__PURE__*/ hoistNonReactStatics(forwarded, WrappedComponent); } return /*#__PURE__*/ hoistNonReactStatics(Connect, WrappedComponent); }; return wrapWithConnect; } /** * * @deprecated * * **We recommend using the `useSelector` and `useDispatch` hooks instead.** * See https://react-redux.js.org/api/hooks * * If you need to use `connect` without this visual deprecation warning, * import `legacy_connect` instead: * * `import { legacy_connect as connect } from 'react-redux'` */ const connect = _connect; /** * Connects a React component to a Redux store. Same as `connect` but without * the deprecation warning. * * **We recommend using the `useSelector` and `useDispatch` hooks instead.** * See https://react-redux.js.org/api/hooks */ const legacy_connect = _connect; //#endregion //#region src/components/Provider.tsx function Provider(providerProps) { if (process.env.NODE_ENV !== "production") { if (typeof useIsomorphicLayoutEffect !== "function") throw new Error("The React Redux `<Provider>` component requires React hooks that are not available in a React Server Component. This usually means you are rendering `<Provider>` in a Server Component. Add the `\"use client\"` directive to the top of the file that renders `<Provider>` (or a parent that ends up rendering it) so it is treated as a Client Component. See https://react.dev/reference/rsc/use-client for more information."); } const { children, context, serverState, store } = providerProps; const contextValue = React.useMemo(() => { const subscription = createSubscription(store); const baseContextValue = { store, subscription, getServerState: serverState != null ? () => serverState : void 0 }; if (process.env.NODE_ENV === "production") return baseContextValue; else { const { identityFunctionCheck = "once", stabilityCheck = "once" } = providerProps; return /* @__PURE__ */ Object.assign(baseContextValue, { stabilityCheck, identityFunctionCheck }); } }, [store, serverState]); const previousState = React.useMemo(() => store.getState(), [store]); useIsomorphicLayoutEffect(() => { const { subscription } = contextValue; subscription.onStateChange = subscription.notifyNestedSubs; subscription.trySubscribe(); if (previousState !== store.getState()) subscription.notifyNestedSubs(); return () => { subscription.tryUnsubscribe(); subscription.onStateChange = void 0; }; }, [contextValue, previousState]); const Context = context || ReactReduxContext; return /* @__PURE__ */ React.createElement(Context.Provider, { value: contextValue }, children); } //#endregion //#region src/hooks/useReduxContext.ts /** * Hook factory, which creates a `useReduxContext` hook bound to a given context. This is a low-level * hook that you should usually not need to call directly. * * @param {React.Context} [context=ReactReduxContext] Context passed to your `<Provider>`. * @returns {Function} A `useReduxContext` hook bound to the specified context. */ function createReduxContextHook(context = ReactReduxContext) { return function useReduxContext() { const contextValue = React.useContext(context); if (process.env.NODE_ENV !== "production" && !contextValue) throw new Error("could not find react-redux context value; please ensure the component is wrapped in a <Provider>"); return contextValue; }; } /** * A hook to access the value of the `ReactReduxContext`. This is a low-level * hook that you should usually not need to call directly. * * @returns {any} the value of the `ReactReduxContext` * * @example * * import React from 'react' * import { useReduxContext } from 'react-redux' * * export const CounterComponent = () => { * const { store } = useReduxContext() * return <div>{store.getState()}</div> * } */ const useReduxContext = /*#__PURE__*/ createReduxContextHook(); //#endregion //#region src/hooks/useStore.ts /** * Hook factory, which creates a `useStore` hook bound to a given context. * * @param {React.Context} [context=ReactReduxContext] Context passed to your `<Provider>`. * @returns {Function} A `useStore` hook bound to the specified context. */ function createStoreHook(context = ReactReduxContext) { const useReduxContext$2 = context === ReactReduxContext ? useReduxContext : createReduxContextHook(context); const useStore = () => { const { store } = useReduxContext$2(); return store; }; Object.assign(useStore, { withTypes: () => useStore }); return useStore; } /** * A hook to access the redux store. * * @returns {any} the redux store * * @example * * import React from 'react' * import { useStore } from 'react-redux' * * export const ExampleComponent = () => { * const store = useStore() * return <div>{store.getState()}</div> * } */ const useStore = /*#__PURE__*/ createStoreHook(); //#endregion //#region src/hooks/useDispatch.ts /** * Hook factory, which creates a `useDispatch` hook bound to a given context. * * @param {React.Context} [context=ReactReduxContext] Context passed to your `<Provider>`. * @returns {Function} A `useDispatch` hook bound to the specified context. */ function createDispatchHook(context = ReactReduxContext) { const useStore$1 = context === ReactReduxContext ? useStore : createStoreHook(context); const useDispatch = () => { return useStore$1().dispatch; }; Object.assign(useDispatch, { withTypes: () => useDispatch }); return useDispatch; } /** * A hook to access the redux `dispatch` function. * * @returns {any|function} redux store's `dispatch` function * * @example * * import React, { useCallback } from 'react' * import { useDispatch } from 'react-redux' * * export const CounterComponent = ({ value }) => { * const dispatch = useDispatch() * const increaseCounter = useCallback(() => dispatch({ type: 'increase-counter' }), []) * return ( * <div> * <span>{value}</span> * <button onClick={increaseCounter}>Increase counter</button> * </div> * ) * } */ const useDispatch = /*#__PURE__*/ createDispatchHook(); //#endregion //#region src/hooks/useSelector.ts const refEquality = (a, b) => a === b; /** * Hook factory, which creates a `useSelector` hook bound to a given context. * * @param {React.Context} [context=ReactReduxContext] Context passed to your `<Provider>`. * @returns {Function} A `useSelector` hook bound to the specified context. */ function createSelectorHook(context = ReactReduxContext) { const useReduxContext$1 = context === ReactReduxContext ? useReduxContext : createReduxContextHook(context); const useSelector = (selector, equalityFnOrOptions = {}) => { const { equalityFn = refEquality } = typeof equalityFnOrOptions === "function" ? { equalityFn: equalityFnOrOptions } : equalityFnOrOptions; if (process.env.NODE_ENV !== "production") { if (!selector) throw new Error(`You must pass a selector to useSelector`); if (typeof selector !== "function") throw new Error(`You must pass a function as a selector to useSelector`); if (typeof equalityFn !== "function") throw new Error(`You must pass a function as an equality function to useSelector`); } const reduxContext = useReduxContext$1(); const { store, subscription, getServerState } = reduxContext; const firstRun = React.useRef(true); const wrappedSelector = React.useCallback({ [selector.name](state) { const selected = selector(state); if (process.env.NODE_ENV !== "production") { const { devModeChecks = {} } = typeof equalityFnOrOptions === "function" ? {} : equalityFnOrOptions; const { identityFunctionCheck, stabilityCheck } = reduxContext; const { identityFunctionCheck: finalIdentityFunctionCheck, stabilityCheck: finalStabilityCheck } = { stabilityCheck, identityFunctionCheck, ...devModeChecks }; if (finalStabilityCheck === "always" || finalStabilityCheck === "once" && firstRun.current) { const toCompare = selector(state); if (!equalityFn(selected, toCompare)) { let stack = void 0; try { throw new Error(); } catch (e) { ({stack} = e); } console.warn("Selector " + (selector.name || "unknown") + " returned a different result when called with the same parameters. This can lead to unnecessary rerenders.\nSelectors that return a new reference (such as an object or an array) should be memoized: https://redux.js.org/usage/deriving-data-selectors#optimizing-selectors-with-memoization", { state, selected, selected2: toCompare, stack }); } } if (finalIdentityFunctionCheck === "always" || finalIdentityFunctionCheck === "once" && firstRun.current) { if (selected === state) { let stack = void 0; try { throw new Error(); } catch (e) { ({stack} = e); } console.warn("Selector " + (selector.name || "unknown") + " returned the root state when called. This can lead to unnecessary rerenders.\nSelectors that return the entire state are almost certainly a mistake, as they will cause a rerender whenever *anything* in state changes.", { stack }); } } if (firstRun.current) firstRun.current = false; } return selected; } }[selector.name], [selector]); const selectedState = useSyncExternalStoreWithSelector(subscription.addNestedSub, store.getState, getServerState || store.getState, wrappedSelector, equalityFn); React.useDebugValue(selectedState); return selectedState; }; Object.assign(useSelector, { withTypes: () => useSelector }); return useSelector; } /** * A hook to access the redux store's state. This hook takes a selector function * as an argument. The selector is called with the store state. * * This hook takes an optional equality comparison function as the second parameter * that allows you to customize the way the selected state is compared to determine * whether the component needs to be re-rendered. * * @param {Function} selector the selector function * @param {Function=} equalityFn the function that will be used to determine equality * * @returns {any} the selected state * * @example * * import React from 'react' * import { useSelector } from 'react-redux' * * export const CounterComponent = () => { * const counter = useSelector(state => state.counter) * return <div>{counter}</div> * } */ const useSelector = /*#__PURE__*/ createSelectorHook(); //#endregion //#region src/exports.ts /** * @deprecated As of React 18, batching is enabled by default for ReactDOM and React Native. * This is now a no-op that immediately runs the callback. */ const batch = defaultNoopBatch; //#endregion export { Provider, ReactReduxContext, batch, connect, createDispatchHook, createSelectorHook, createStoreHook, legacy_connect, shallowEqual, useDispatch, useSelector, useStore }; //# sourceMappingURL=react-redux.mjs.map