123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- "use strict";
- exports.__esModule = true;
- exports.createSelectorHook = createSelectorHook;
- exports.useSelector = void 0;
- var _react = require("react");
- var _useReduxContext2 = require("./useReduxContext");
- var _Subscription = require("../utils/Subscription");
- var _useIsomorphicLayoutEffect = require("../utils/useIsomorphicLayoutEffect");
- var _Context = require("../components/Context");
- var refEquality = function refEquality(a, b) {
- return a === b;
- };
- function useSelectorWithStoreAndSubscription(selector, equalityFn, store, contextSub) {
- var _useReducer = (0, _react.useReducer)(function (s) {
- return s + 1;
- }, 0),
- forceRender = _useReducer[1];
- var subscription = (0, _react.useMemo)(function () {
- return (0, _Subscription.createSubscription)(store, contextSub);
- }, [store, contextSub]);
- var latestSubscriptionCallbackError = (0, _react.useRef)();
- var latestSelector = (0, _react.useRef)();
- var latestStoreState = (0, _react.useRef)();
- var latestSelectedState = (0, _react.useRef)();
- var storeState = store.getState();
- var selectedState;
- try {
- if (selector !== latestSelector.current || storeState !== latestStoreState.current || latestSubscriptionCallbackError.current) {
- var newSelectedState = selector(storeState); // ensure latest selected state is reused so that a custom equality function can result in identical references
- if (latestSelectedState.current === undefined || !equalityFn(newSelectedState, latestSelectedState.current)) {
- selectedState = newSelectedState;
- } else {
- selectedState = latestSelectedState.current;
- }
- } 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;
- }
- (0, _useIsomorphicLayoutEffect.useIsomorphicLayoutEffect)(function () {
- latestSelector.current = selector;
- latestStoreState.current = storeState;
- latestSelectedState.current = selectedState;
- latestSubscriptionCallbackError.current = undefined;
- });
- (0, _useIsomorphicLayoutEffect.useIsomorphicLayoutEffect)(function () {
- function checkForUpdates() {
- try {
- var newStoreState = store.getState(); // Avoid calling selector multiple times if the store's state has not changed
- if (newStoreState === latestStoreState.current) {
- return;
- }
- var _newSelectedState = latestSelector.current(newStoreState);
- if (equalityFn(_newSelectedState, latestSelectedState.current)) {
- return;
- }
- latestSelectedState.current = _newSelectedState;
- latestStoreState.current = newStoreState;
- } 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 `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) {
- if (context === void 0) {
- context = _Context.ReactReduxContext;
- }
- var useReduxContext = context === _Context.ReactReduxContext ? _useReduxContext2.useReduxContext : function () {
- return (0, _react.useContext)(context);
- };
- return function useSelector(selector, equalityFn) {
- if (equalityFn === void 0) {
- equalityFn = refEquality;
- }
- 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");
- }
- }
- var _useReduxContext = useReduxContext(),
- store = _useReduxContext.store,
- contextSub = _useReduxContext.subscription;
- var selectedState = useSelectorWithStoreAndSubscription(selector, equalityFn, store, contextSub);
- (0, _react.useDebugValue)(selectedState);
- return selectedState;
- };
- }
- /**
- * 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>
- * }
- */
- var useSelector = /*#__PURE__*/createSelectorHook();
- exports.useSelector = useSelector;
|