| @@ -1397,9 +1397,9 @@ | ||
| 1397 | 1397 | selector.registry = registry; |
| 1398 | 1398 | } |
| 1399 | 1399 | return selector(state.root, ...args); |
| 1400 | 1400 | }; |
| 1401 | - boundSelector.__unstableNormalizeArgs = selector.__unstableNormalizeArgs; | |
| 1401 | + boundSelector.normalizeArgs = getNormalizeArgs(selector); | |
| 1402 | 1402 | const resolver = resolvers[selectorName]; |
| 1403 | 1403 | if (!resolver) { |
| 1404 | 1404 | boundSelector.hasResolver = false; |
| 1405 | 1405 | return boundSelector; |
| @@ -1422,8 +1422,15 @@ | ||
| 1422 | 1422 | targetSelector, |
| 1423 | 1423 | selectorArgs |
| 1424 | 1424 | ); |
| 1425 | 1425 | } |
| 1426 | + const resolver = resolvers[selectorName]; | |
| 1427 | + if (resolver && selectorArgs) { | |
| 1428 | + selectorArgs = normalizeResolutionArgs( | |
| 1429 | + resolver, | |
| 1430 | + selectorArgs | |
| 1431 | + ); | |
| 1432 | + } | |
| 1426 | 1433 | } |
| 1427 | 1434 | const state = store.__unstableOriginalGetState(); |
| 1428 | 1435 | return metaDataSelector( |
| 1429 | 1436 | state.metadata, |
| @@ -1581,13 +1588,20 @@ | ||
| 1581 | 1588 | return async (...args) => selector(...args); |
| 1582 | 1589 | } |
| 1583 | 1590 | return (...args) => new Promise((resolve, reject) => { |
| 1584 | 1591 | const resolver = resolvers[selectorName]; |
| 1592 | + const resolutionArgs = normalizeResolutionArgs( | |
| 1593 | + resolver, | |
| 1594 | + normalize(selector, args) | |
| 1595 | + ); | |
| 1585 | 1596 | const hasFinished = () => { |
| 1586 | 1597 | return boundMetadataSelectors.hasFinishedResolution( |
| 1587 | 1598 | selectorName, |
| 1588 | 1599 | args |
| 1589 | - ) || typeof resolver.isFulfilled === "function" && resolver.isFulfilled(store.getState(), ...args); | |
| 1600 | + ) || typeof resolver.isFulfilled === "function" && resolver.isFulfilled( | |
| 1601 | + store.getState(), | |
| 1602 | + ...resolutionArgs | |
| 1603 | + ); | |
| 1590 | 1604 | }; |
| 1591 | 1605 | const finalize = (result2) => { |
| 1592 | 1606 | const hasFailed = boundMetadataSelectors.hasResolutionFailed( |
| 1593 | 1607 | selectorName, |
| @@ -1664,10 +1678,14 @@ | ||
| 1664 | 1678 | // Add the fulfill method. |
| 1665 | 1679 | }; |
| 1666 | 1680 | } |
| 1667 | 1681 | function mapSelectorWithResolver(selector, selectorName, resolver, store, resolversCache, boundMetadataSelectors) { |
| 1668 | - function fulfillSelector(args) { | |
| 1669 | - if (resolversCache.isRunning(selectorName, args) || boundMetadataSelectors.hasStartedResolution(selectorName, args) || typeof resolver.isFulfilled === "function" && resolver.isFulfilled(store.getState(), ...args)) { | |
| 1682 | + function fulfillSelector(selectorArgs) { | |
| 1683 | + const args = normalizeResolutionArgs(resolver, selectorArgs); | |
| 1684 | + if (resolversCache.isRunning(selectorName, args) || boundMetadataSelectors.hasStartedResolution( | |
| 1685 | + selectorName, | |
| 1686 | + selectorArgs | |
| 1687 | + ) || typeof resolver.isFulfilled === "function" && resolver.isFulfilled(store.getState(), ...args)) { | |
| 1670 | 1688 | return; |
| 1671 | 1689 | } |
| 1672 | 1690 | resolversCache.markAsRunning(selectorName, args); |
| 1673 | 1691 | setTimeout(async () => { |
| @@ -1695,16 +1713,27 @@ | ||
| 1695 | 1713 | fulfillSelector(args); |
| 1696 | 1714 | return selector(...args); |
| 1697 | 1715 | }; |
| 1698 | 1716 | selectorResolver.hasResolver = true; |
| 1717 | + selectorResolver.normalizeArgs = selector.normalizeArgs; | |
| 1699 | 1718 | return selectorResolver; |
| 1700 | 1719 | } |
| 1720 | + function getNormalizeArgs(selector) { | |
| 1721 | + return selector.normalizeArgs ?? selector.__unstableNormalizeArgs; | |
| 1722 | + } | |
| 1701 | 1723 | function normalize(selector, args) { |
| 1702 | - if (selector.__unstableNormalizeArgs && typeof selector.__unstableNormalizeArgs === "function" && args?.length) { | |
| 1703 | - return selector.__unstableNormalizeArgs(args); | |
| 1724 | + const normalizeArgs = getNormalizeArgs(selector); | |
| 1725 | + if (typeof normalizeArgs === "function" && args?.length) { | |
| 1726 | + return normalizeArgs(args); | |
| 1704 | 1727 | } |
| 1705 | 1728 | return args; |
| 1706 | 1729 | } |
| 1730 | + function normalizeResolutionArgs(resolver, args) { | |
| 1731 | + if (typeof resolver.getResolutionArgs === "function") { | |
| 1732 | + return resolver.getResolutionArgs(...args); | |
| 1733 | + } | |
| 1734 | + return args; | |
| 1735 | + } | |
| 1707 | 1736 | |
| 1708 | 1737 | // packages/data/build-module/store/index.mjs |
| 1709 | 1738 | var coreDataStore = { |
| 1710 | 1739 | name: "core/data", |
| @@ -1757,14 +1786,16 @@ | ||
| 1757 | 1786 | function createEmitter() { |
| 1758 | 1787 | let isPaused = false; |
| 1759 | 1788 | let isPending = false; |
| 1760 | 1789 | const listeners = /* @__PURE__ */ new Set(); |
| 1761 | - const notifyListeners = () => ( | |
| 1762 | - // We use Array.from to clone the listeners Set | |
| 1763 | - // This ensures that we don't run a listener | |
| 1764 | - // that was added as a response to another listener. | |
| 1765 | - Array.from(listeners).forEach((listener) => listener()) | |
| 1766 | - ); | |
| 1790 | + let clonedListeners = null; | |
| 1791 | + const notifyListeners = () => { | |
| 1792 | + clonedListeners ??= Array.from(listeners); | |
| 1793 | + const currentListeners = clonedListeners; | |
| 1794 | + for (let i = 0; i < currentListeners.length; i++) { | |
| 1795 | + currentListeners[i](); | |
| 1796 | + } | |
| 1797 | + }; | |
| 1767 | 1798 | return { |
| 1768 | 1799 | get isPaused() { |
| 1769 | 1800 | return isPaused; |
| 1770 | 1801 | }, |
| @@ -1769,9 +1800,13 @@ | ||
| 1769 | 1800 | return isPaused; |
| 1770 | 1801 | }, |
| 1771 | 1802 | subscribe(listener) { |
| 1772 | 1803 | listeners.add(listener); |
| 1773 | - return () => listeners.delete(listener); | |
| 1804 | + clonedListeners = null; | |
| 1805 | + return () => { | |
| 1806 | + listeners.delete(listener); | |
| 1807 | + clonedListeners = null; | |
| 1808 | + }; | |
| 1774 | 1809 | }, |
| 1775 | 1810 | pause() { |
| 1776 | 1811 | isPaused = true; |
| 1777 | 1812 | }, |
| @@ -1799,11 +1834,41 @@ | ||
| 1799 | 1834 | function createRegistry(storeConfigs = {}, parent = null) { |
| 1800 | 1835 | const stores = {}; |
| 1801 | 1836 | const emitter = createEmitter(); |
| 1802 | 1837 | let listeningStores = null; |
| 1838 | + const pendingListeners = /* @__PURE__ */ new Map(); | |
| 1803 | 1839 | function globalListener() { |
| 1804 | 1840 | emitter.emit(); |
| 1805 | 1841 | } |
| 1842 | + function subscribePending(storeName, listener) { | |
| 1843 | + const pending = { listener }; | |
| 1844 | + let listeners = pendingListeners.get(storeName); | |
| 1845 | + if (!listeners) { | |
| 1846 | + listeners = /* @__PURE__ */ new Set(); | |
| 1847 | + pendingListeners.set(storeName, listeners); | |
| 1848 | + } | |
| 1849 | + listeners.add(pending); | |
| 1850 | + return () => { | |
| 1851 | + pending.unsubscribe?.(); | |
| 1852 | + const stillPending = pendingListeners.get(storeName); | |
| 1853 | + if (stillPending) { | |
| 1854 | + stillPending.delete(pending); | |
| 1855 | + if (stillPending.size === 0) { | |
| 1856 | + pendingListeners.delete(storeName); | |
| 1857 | + } | |
| 1858 | + } | |
| 1859 | + }; | |
| 1860 | + } | |
| 1861 | + function connectPendingListeners(name, store) { | |
| 1862 | + const listeners = pendingListeners.get(name); | |
| 1863 | + if (!listeners) { | |
| 1864 | + return; | |
| 1865 | + } | |
| 1866 | + pendingListeners.delete(name); | |
| 1867 | + for (const pending of listeners) { | |
| 1868 | + pending.unsubscribe = store.subscribe(pending.listener); | |
| 1869 | + } | |
| 1870 | + } | |
| 1806 | 1871 | const subscribe2 = (listener, storeNameOrDescriptor) => { |
| 1807 | 1872 | if (!storeNameOrDescriptor) { |
| 1808 | 1873 | return emitter.subscribe(listener); |
| 1809 | 1874 | } |
| @@ -1812,9 +1877,9 @@ | ||
| 1812 | 1877 | if (store) { |
| 1813 | 1878 | return store.subscribe(listener); |
| 1814 | 1879 | } |
| 1815 | 1880 | if (!parent) { |
| 1816 | - return emitter.subscribe(listener); | |
| 1881 | + return subscribePending(storeName, listener); | |
| 1817 | 1882 | } |
| 1818 | 1883 | return parent.subscribe(listener, storeNameOrDescriptor); |
| 1819 | 1884 | }; |
| 1820 | 1885 | function select3(storeNameOrDescriptor) { |
| @@ -1891,25 +1956,13 @@ | ||
| 1891 | 1956 | if (typeof store.subscribe !== "function") { |
| 1892 | 1957 | throw new TypeError("store.subscribe must be a function"); |
| 1893 | 1958 | } |
| 1894 | 1959 | store.emitter = createEmitter(); |
| 1895 | - const currentSubscribe = store.subscribe; | |
| 1896 | - store.subscribe = (listener) => { | |
| 1897 | - const unsubscribeFromEmitter = store.emitter.subscribe(listener); | |
| 1898 | - const unsubscribeFromStore = currentSubscribe(() => { | |
| 1899 | - if (store.emitter.isPaused) { | |
| 1900 | - store.emitter.emit(); | |
| 1901 | - return; | |
| 1902 | - } | |
| 1903 | - listener(); | |
| 1904 | - }); | |
| 1905 | - return () => { | |
| 1906 | - unsubscribeFromStore?.(); | |
| 1907 | - unsubscribeFromEmitter?.(); | |
| 1908 | - }; | |
| 1909 | - }; | |
| 1960 | + store.subscribe(() => store.emitter.emit()); | |
| 1961 | + store.subscribe = (listener) => store.emitter.subscribe(listener); | |
| 1910 | 1962 | stores[name] = store; |
| 1911 | 1963 | store.subscribe(globalListener); |
| 1964 | + connectPendingListeners(name, store); | |
| 1912 | 1965 | if (parent) { |
| 1913 | 1966 | try { |
| 1914 | 1967 | unlock(store.store).registerPrivateActions( |
| 1915 | 1968 | unlock(parent).privateActionsOf(name) |
| @@ -2220,10 +2273,9 @@ | ||
| 2220 | 2273 | // packages/data/build-module/components/async-mode-provider/context.mjs |
| 2221 | 2274 | var import_element3 = __toESM(require_element(), 1); |
| 2222 | 2275 | var Context2 = (0, import_element3.createContext)(false); |
| 2223 | 2276 | Context2.displayName = "AsyncModeContext"; |
| 2224 | - var { Consumer: Consumer2, Provider: Provider2 } = Context2; | |
| 2225 | - var context_default2 = Provider2; | |
| 2277 | + var context_default2 = Context2.Provider; | |
| 2226 | 2278 | |
| 2227 | 2279 | // packages/data/build-module/components/async-mode-provider/use-async-mode.mjs |
| 2228 | 2280 | function useAsyncMode() { |
| 2229 | 2281 | return (0, import_element4.useContext)(Context2); |
| @@ -2240,8 +2292,41 @@ | ||
| 2240 | 2292 | "The `useSelect` hook returns different values when called with the same state and parameters.\nThis can lead to unnecessary re-renders and performance issues if not fixed.\n\nNon-equal value keys: %s\n\n", |
| 2241 | 2293 | keys.join(", ") |
| 2242 | 2294 | ); |
| 2243 | 2295 | } |
| 2296 | + var deferredBuckets = /* @__PURE__ */ new WeakMap(); | |
| 2297 | + function subscribeDeferred(registry, storeName, listener) { | |
| 2298 | + let buckets = deferredBuckets.get(registry); | |
| 2299 | + if (!buckets) { | |
| 2300 | + buckets = /* @__PURE__ */ new Map(); | |
| 2301 | + deferredBuckets.set(registry, buckets); | |
| 2302 | + } | |
| 2303 | + let addToBucket = buckets.get(storeName); | |
| 2304 | + if (!addToBucket) { | |
| 2305 | + const listeners = /* @__PURE__ */ new Set(); | |
| 2306 | + const flush = () => { | |
| 2307 | + for (const { context, callback } of listeners) { | |
| 2308 | + renderQueue.add(context, callback); | |
| 2309 | + } | |
| 2310 | + }; | |
| 2311 | + const unsubscribe = registry.subscribe( | |
| 2312 | + () => renderQueue.add(listeners, flush), | |
| 2313 | + storeName | |
| 2314 | + ); | |
| 2315 | + addToBucket = (newListener) => { | |
| 2316 | + listeners.add(newListener); | |
| 2317 | + return () => { | |
| 2318 | + if (listeners.delete(newListener) && listeners.size === 0) { | |
| 2319 | + buckets.delete(storeName); | |
| 2320 | + renderQueue.cancel(listeners); | |
| 2321 | + unsubscribe(); | |
| 2322 | + } | |
| 2323 | + }; | |
| 2324 | + }; | |
| 2325 | + buckets.set(storeName, addToBucket); | |
| 2326 | + } | |
| 2327 | + return addToBucket(listener); | |
| 2328 | + } | |
| 2244 | 2329 | function Store(registry, suspense) { |
| 2245 | 2330 | const select3 = suspense ? registry.suspendSelect : registry.select; |
| 2246 | 2331 | const queueContext = {}; |
| 2247 | 2332 | let lastMapSelect; |
| @@ -2269,25 +2354,34 @@ | ||
| 2269 | 2354 | const onStoreChange = () => { |
| 2270 | 2355 | lastMapResultValid = false; |
| 2271 | 2356 | listener(); |
| 2272 | 2357 | }; |
| 2273 | - const onChange = () => { | |
| 2358 | + function listenToStore(storeName) { | |
| 2274 | 2359 | if (lastIsAsync) { |
| 2275 | - renderQueue.add(queueContext, onStoreChange); | |
| 2276 | - } else { | |
| 2277 | - onStoreChange(); | |
| 2360 | + return subscribeDeferred(registry, storeName, { | |
| 2361 | + context: queueContext, | |
| 2362 | + callback: onStoreChange | |
| 2363 | + }); | |
| 2278 | 2364 | } |
| 2279 | - }; | |
| 2280 | - const unsubs = []; | |
| 2365 | + return registry.subscribe(onStoreChange, storeName); | |
| 2366 | + } | |
| 2367 | + const unsubs = /* @__PURE__ */ new Map(); | |
| 2281 | 2368 | function subscribeStore(storeName) { |
| 2282 | - unsubs.push(registry.subscribe(onChange, storeName)); | |
| 2369 | + unsubs.set(storeName, listenToStore(storeName)); | |
| 2283 | 2370 | } |
| 2371 | + function resubscribeStores() { | |
| 2372 | + for (const [storeName, unsub] of unsubs) { | |
| 2373 | + unsub?.(); | |
| 2374 | + unsubs.set(storeName, listenToStore(storeName)); | |
| 2375 | + } | |
| 2376 | + } | |
| 2284 | 2377 | for (const storeName of activeStores) { |
| 2285 | 2378 | subscribeStore(storeName); |
| 2286 | 2379 | } |
| 2287 | - activeSubscriptions.add(subscribeStore); | |
| 2380 | + const subscription = { subscribeStore, resubscribeStores }; | |
| 2381 | + activeSubscriptions.add(subscription); | |
| 2288 | 2382 | return () => { |
| 2289 | - activeSubscriptions.delete(subscribeStore); | |
| 2383 | + activeSubscriptions.delete(subscription); | |
| 2290 | 2384 | for (const unsub of unsubs.values()) { |
| 2291 | 2385 | unsub?.(); |
| 2292 | 2386 | } |
| 2293 | 2387 | renderQueue.cancel(queueContext); |
| @@ -2299,13 +2393,18 @@ | ||
| 2299 | 2393 | continue; |
| 2300 | 2394 | } |
| 2301 | 2395 | activeStores.push(newStore); |
| 2302 | 2396 | for (const subscription of activeSubscriptions) { |
| 2303 | - subscription(newStore); | |
| 2397 | + subscription.subscribeStore(newStore); | |
| 2304 | 2398 | } |
| 2305 | 2399 | } |
| 2306 | 2400 | } |
| 2307 | - return { subscribe: subscribe2, updateStores }; | |
| 2401 | + function switchMode() { | |
| 2402 | + for (const subscription of activeSubscriptions) { | |
| 2403 | + subscription.resubscribeStores(); | |
| 2404 | + } | |
| 2405 | + } | |
| 2406 | + return { subscribe: subscribe2, updateStores, switchMode }; | |
| 2308 | 2407 | }; |
| 2309 | 2408 | return (mapSelect, isAsync) => { |
| 2310 | 2409 | function updateValue() { |
| 2311 | 2410 | if (lastMapResultValid && mapSelect === lastMapSelect) { |
| @@ -2342,14 +2441,18 @@ | ||
| 2342 | 2441 | function getValue() { |
| 2343 | 2442 | updateValue(); |
| 2344 | 2443 | return lastMapResult; |
| 2345 | 2444 | } |
| 2346 | - if (lastIsAsync && !isAsync) { | |
| 2445 | + const wasAsync = lastIsAsync; | |
| 2446 | + lastIsAsync = isAsync; | |
| 2447 | + if (wasAsync && !isAsync) { | |
| 2347 | 2448 | lastMapResultValid = false; |
| 2348 | 2449 | renderQueue.cancel(queueContext); |
| 2349 | 2450 | } |
| 2350 | 2451 | updateValue(); |
| 2351 | - lastIsAsync = isAsync; | |
| 2452 | + if (wasAsync !== isAsync) { | |
| 2453 | + subscriber.switchMode(); | |
| 2454 | + } | |
| 2352 | 2455 | return { subscribe: subscriber.subscribe, getValue }; |
| 2353 | 2456 | }; |
| 2354 | 2457 | } |
| 2355 | 2458 | function _useStaticSelect(storeName) { |