Skip to content

Commit 8f48003

Browse files
authored
Merge pull request #2789 from reduxjs/feature/v1.9-pre-beta-cleanup
2 parents e126f17 + feccd87 commit 8f48003

12 files changed

+98
-165
lines changed

packages/toolkit/src/query/core/buildMiddleware/batchActions.ts

+64-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import type { QueryThunk, RejectedAction } from '../buildThunks'
22
import type { InternalHandlerBuilder } from './types'
3-
import type { SubscriptionState } from '../apiState'
3+
import type {
4+
SubscriptionState,
5+
QuerySubstateIdentifier,
6+
Subscribers,
7+
} from '../apiState'
48
import { produceWithPatches } from 'immer'
9+
import { createSlice, PayloadAction, AnyAction } from '@reduxjs/toolkit'
510

611
// Copied from https://github.com/feross/queue-microtask
712
let promise: Promise<any>
@@ -18,16 +23,71 @@ const queueMicrotaskShim =
1823

1924
export const buildBatchedActionsHandler: InternalHandlerBuilder<
2025
[actionShouldContinue: boolean, subscriptionExists: boolean]
21-
> = ({ api, queryThunk }) => {
22-
const { actuallyMutateSubscriptions } = api.internalActions
26+
> = ({ api, queryThunk, internalState }) => {
2327
const subscriptionsPrefix = `${api.reducerPath}/subscriptions`
2428

2529
let previousSubscriptions: SubscriptionState =
2630
null as unknown as SubscriptionState
2731

2832
let dispatchQueued = false
2933

30-
return (action, mwApi, internalState) => {
34+
const { updateSubscriptionOptions, unsubscribeQueryResult } =
35+
api.internalActions
36+
37+
// Actually intentionally mutate the subscriptions state used in the middleware
38+
// This is done to speed up perf when loading many components
39+
const actuallyMutateSubscriptions = (
40+
mutableState: SubscriptionState,
41+
action: AnyAction
42+
) => {
43+
if (updateSubscriptionOptions.match(action)) {
44+
const { queryCacheKey, requestId, options } = action.payload
45+
46+
if (mutableState?.[queryCacheKey]?.[requestId]) {
47+
mutableState[queryCacheKey]![requestId] = options
48+
}
49+
return true
50+
}
51+
if (unsubscribeQueryResult.match(action)) {
52+
const { queryCacheKey, requestId } = action.payload
53+
if (mutableState[queryCacheKey]) {
54+
delete mutableState[queryCacheKey]![requestId]
55+
}
56+
return true
57+
}
58+
if (api.internalActions.removeQueryResult.match(action)) {
59+
delete mutableState[action.payload.queryCacheKey]
60+
return true
61+
}
62+
if (queryThunk.pending.match(action)) {
63+
const {
64+
meta: { arg, requestId },
65+
} = action
66+
if (arg.subscribe) {
67+
const substate = (mutableState[arg.queryCacheKey] ??= {})
68+
substate[requestId] =
69+
arg.subscriptionOptions ?? substate[requestId] ?? {}
70+
71+
return true
72+
}
73+
}
74+
if (queryThunk.rejected.match(action)) {
75+
const {
76+
meta: { condition, arg, requestId },
77+
} = action
78+
if (condition && arg.subscribe) {
79+
const substate = (mutableState[arg.queryCacheKey] ??= {})
80+
substate[requestId] =
81+
arg.subscriptionOptions ?? substate[requestId] ?? {}
82+
83+
return true
84+
}
85+
}
86+
87+
return false
88+
}
89+
90+
return (action, mwApi) => {
3191
if (!previousSubscriptions) {
3292
// Initialize it the first time this handler runs
3393
previousSubscriptions = JSON.parse(

packages/toolkit/src/query/core/buildMiddleware/cacheCollection.ts

+4-9
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,11 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
5050
reducerPath,
5151
api,
5252
context,
53+
internalState,
5354
}) => {
5455
const { removeQueryResult, unsubscribeQueryResult } = api.internalActions
5556

56-
function anySubscriptionsRemainingForKey(
57-
queryCacheKey: string,
58-
internalState: InternalMiddlewareState
59-
) {
57+
function anySubscriptionsRemainingForKey(queryCacheKey: string) {
6058
const subscriptions = internalState.currentSubscriptions[queryCacheKey]
6159
return !!subscriptions && !isObjectEmpty(subscriptions)
6260
}
@@ -76,7 +74,6 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
7674
queryCacheKey,
7775
state.queries[queryCacheKey]?.endpointName,
7876
mwApi,
79-
internalState,
8077
state.config
8178
)
8279
}
@@ -99,7 +96,6 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
9996
queryCacheKey as QueryCacheKey,
10097
queryState?.endpointName,
10198
mwApi,
102-
internalState,
10399
state.config
104100
)
105101
}
@@ -110,7 +106,6 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
110106
queryCacheKey: QueryCacheKey,
111107
endpointName: string | undefined,
112108
api: SubMiddlewareApi,
113-
internalState: InternalMiddlewareState,
114109
config: ConfigState<string>
115110
) {
116111
const endpointDefinition = context.endpointDefinitions[
@@ -132,13 +127,13 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
132127
Math.min(keepUnusedDataFor, THIRTY_TWO_BIT_MAX_TIMER_SECONDS)
133128
)
134129

135-
if (!anySubscriptionsRemainingForKey(queryCacheKey, internalState)) {
130+
if (!anySubscriptionsRemainingForKey(queryCacheKey)) {
136131
const currentTimeout = currentRemovalTimeouts[queryCacheKey]
137132
if (currentTimeout) {
138133
clearTimeout(currentTimeout)
139134
}
140135
currentRemovalTimeouts[queryCacheKey] = setTimeout(() => {
141-
if (!anySubscriptionsRemainingForKey(queryCacheKey, internalState)) {
136+
if (!anySubscriptionsRemainingForKey(queryCacheKey)) {
142137
api.dispatch(removeQueryResult({ queryCacheKey }))
143138
}
144139
delete currentRemovalTimeouts![queryCacheKey]

packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ export const buildCacheLifecycleHandler: InternalHandlerBuilder = ({
183183
context,
184184
queryThunk,
185185
mutationThunk,
186+
internalState,
186187
}) => {
187188
const isQueryThunk = isAsyncThunkAction(queryThunk)
188189
const isMutationThunk = isAsyncThunkAction(mutationThunk)
@@ -197,7 +198,6 @@ export const buildCacheLifecycleHandler: InternalHandlerBuilder = ({
197198
const handler: ApiMiddlewareInternalHandler = (
198199
action,
199200
mwApi,
200-
internalState,
201201
stateBefore
202202
) => {
203203
const cacheKey = getCacheKey(action)

packages/toolkit/src/query/core/buildMiddleware/index.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,17 @@ export function buildMiddleware<
5959
> = (mwApi) => {
6060
let initialized = false
6161

62+
let internalState: InternalMiddlewareState = {
63+
currentSubscriptions: {},
64+
}
65+
6266
const builderArgs = {
6367
...(input as any as BuildMiddlewareInput<
6468
EndpointDefinitions,
6569
string,
6670
string
6771
>),
72+
internalState,
6873
refetchQuery,
6974
}
7075

@@ -73,10 +78,6 @@ export function buildMiddleware<
7378
const batchedActionsHandler = buildBatchedActionsHandler(builderArgs)
7479
const windowEventsHandler = buildWindowEventHandler(builderArgs)
7580

76-
let internalState: InternalMiddlewareState = {
77-
currentSubscriptions: {},
78-
}
79-
8081
return (next) => {
8182
return (action) => {
8283
if (!initialized) {
@@ -92,7 +93,6 @@ export function buildMiddleware<
9293
const [actionShouldContinue, hasSubscription] = batchedActionsHandler(
9394
action,
9495
mwApiWithNext,
95-
internalState,
9696
stateBefore
9797
)
9898

@@ -108,7 +108,7 @@ export function buildMiddleware<
108108
// Only run these checks if the middleware is registered okay
109109

110110
// This looks for actions that aren't specific to the API slice
111-
windowEventsHandler(action, mwApiWithNext, internalState, stateBefore)
111+
windowEventsHandler(action, mwApiWithNext, stateBefore)
112112

113113
if (
114114
isThisApiSliceAction(action) ||
@@ -117,7 +117,7 @@ export function buildMiddleware<
117117
// Only run these additional checks if the actions are part of the API slice,
118118
// or the action has hydration-related data
119119
for (let handler of handlers) {
120-
handler(action, mwApiWithNext, internalState, stateBefore)
120+
handler(action, mwApiWithNext, stateBefore)
121121
}
122122
}
123123
}

packages/toolkit/src/query/core/buildMiddleware/polling.ts

+8-13
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,34 @@ export const buildPollingHandler: InternalHandlerBuilder = ({
1414
queryThunk,
1515
api,
1616
refetchQuery,
17+
internalState,
1718
}) => {
1819
const currentPolls: QueryStateMeta<{
1920
nextPollTimestamp: number
2021
timeout?: TimeoutId
2122
pollingInterval: number
2223
}> = {}
2324

24-
const handler: ApiMiddlewareInternalHandler = (
25-
action,
26-
mwApi,
27-
internalState
28-
) => {
25+
const handler: ApiMiddlewareInternalHandler = (action, mwApi) => {
2926
if (
3027
api.internalActions.updateSubscriptionOptions.match(action) ||
3128
api.internalActions.unsubscribeQueryResult.match(action)
3229
) {
33-
updatePollingInterval(action.payload, mwApi, internalState)
30+
updatePollingInterval(action.payload, mwApi)
3431
}
3532

3633
if (
3734
queryThunk.pending.match(action) ||
3835
(queryThunk.rejected.match(action) && action.meta.condition)
3936
) {
40-
updatePollingInterval(action.meta.arg, mwApi, internalState)
37+
updatePollingInterval(action.meta.arg, mwApi)
4138
}
4239

4340
if (
4441
queryThunk.fulfilled.match(action) ||
4542
(queryThunk.rejected.match(action) && !action.meta.condition)
4643
) {
47-
startNextPoll(action.meta.arg, mwApi, internalState)
44+
startNextPoll(action.meta.arg, mwApi)
4845
}
4946

5047
if (api.util.resetApiState.match(action)) {
@@ -54,8 +51,7 @@ export const buildPollingHandler: InternalHandlerBuilder = ({
5451

5552
function startNextPoll(
5653
{ queryCacheKey }: QuerySubstateIdentifier,
57-
api: SubMiddlewareApi,
58-
internalState: InternalMiddlewareState
54+
api: SubMiddlewareApi
5955
) {
6056
const state = api.getState()[reducerPath]
6157
const querySubState = state.queries[queryCacheKey]
@@ -90,8 +86,7 @@ export const buildPollingHandler: InternalHandlerBuilder = ({
9086

9187
function updatePollingInterval(
9288
{ queryCacheKey }: QuerySubstateIdentifier,
93-
api: SubMiddlewareApi,
94-
internalState: InternalMiddlewareState
89+
api: SubMiddlewareApi
9590
) {
9691
const state = api.getState()[reducerPath]
9792
const querySubState = state.queries[queryCacheKey]
@@ -112,7 +107,7 @@ export const buildPollingHandler: InternalHandlerBuilder = ({
112107
const nextPollTimestamp = Date.now() + lowestPollingInterval
113108

114109
if (!currentPoll || nextPollTimestamp < currentPoll.nextPollTimestamp) {
115-
startNextPoll({ queryCacheKey }, api, internalState)
110+
startNextPoll({ queryCacheKey }, api)
116111
}
117112
}
118113

packages/toolkit/src/query/core/buildMiddleware/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export type SubMiddlewareApi = MiddlewareAPI<
5252

5353
export interface BuildSubMiddlewareInput
5454
extends BuildMiddlewareInput<EndpointDefinitions, string, string> {
55+
internalState: InternalMiddlewareState
5556
refetchQuery(
5657
querySubState: Exclude<
5758
QuerySubState<any>,
@@ -73,7 +74,6 @@ export type SubMiddlewareBuilder = (
7374
export type ApiMiddlewareInternalHandler<ReturnType = void> = (
7475
action: AnyAction,
7576
mwApi: SubMiddlewareApi & { next: Dispatch<AnyAction> },
76-
internalState: InternalMiddlewareState,
7777
prevState: RootState<EndpointDefinitions, string, string>
7878
) => ReturnType
7979

packages/toolkit/src/query/core/buildMiddleware/windowEventHandling.ts

+5-10
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { onFocus, onOnline } from '../setupListeners'
44
import type {
55
ApiMiddlewareInternalHandler,
66
InternalHandlerBuilder,
7-
InternalMiddlewareState,
87
SubMiddlewareApi,
98
} from './types'
109

@@ -13,26 +12,22 @@ export const buildWindowEventHandler: InternalHandlerBuilder = ({
1312
context,
1413
api,
1514
refetchQuery,
15+
internalState,
1616
}) => {
1717
const { removeQueryResult } = api.internalActions
1818

19-
const handler: ApiMiddlewareInternalHandler = (
20-
action,
21-
mwApi,
22-
internalState
23-
) => {
19+
const handler: ApiMiddlewareInternalHandler = (action, mwApi) => {
2420
if (onFocus.match(action)) {
25-
refetchValidQueries(mwApi, 'refetchOnFocus', internalState)
21+
refetchValidQueries(mwApi, 'refetchOnFocus')
2622
}
2723
if (onOnline.match(action)) {
28-
refetchValidQueries(mwApi, 'refetchOnReconnect', internalState)
24+
refetchValidQueries(mwApi, 'refetchOnReconnect')
2925
}
3026
}
3127

3228
function refetchValidQueries(
3329
api: SubMiddlewareApi,
34-
type: 'refetchOnFocus' | 'refetchOnReconnect',
35-
internalState: InternalMiddlewareState
30+
type: 'refetchOnFocus' | 'refetchOnReconnect'
3631
) {
3732
const state = api.getState()[reducerPath]
3833
const queries = state.queries

0 commit comments

Comments
 (0)