Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

General pre-1.9-beta cleanup #2789

Merged
merged 4 commits into from
Oct 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
68 changes: 64 additions & 4 deletions packages/toolkit/src/query/core/buildMiddleware/batchActions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import type { QueryThunk, RejectedAction } from '../buildThunks'
import type { InternalHandlerBuilder } from './types'
import type { SubscriptionState } from '../apiState'
import type {
SubscriptionState,
QuerySubstateIdentifier,
Subscribers,
} from '../apiState'
import { produceWithPatches } from 'immer'
import { createSlice, PayloadAction, AnyAction } from '@reduxjs/toolkit'

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

export const buildBatchedActionsHandler: InternalHandlerBuilder<
[actionShouldContinue: boolean, subscriptionExists: boolean]
> = ({ api, queryThunk }) => {
const { actuallyMutateSubscriptions } = api.internalActions
> = ({ api, queryThunk, internalState }) => {
const subscriptionsPrefix = `${api.reducerPath}/subscriptions`

let previousSubscriptions: SubscriptionState =
null as unknown as SubscriptionState

let dispatchQueued = false

return (action, mwApi, internalState) => {
const { updateSubscriptionOptions, unsubscribeQueryResult } =
api.internalActions

// Actually intentionally mutate the subscriptions state used in the middleware
// This is done to speed up perf when loading many components
const actuallyMutateSubscriptions = (
mutableState: SubscriptionState,
action: AnyAction
) => {
if (updateSubscriptionOptions.match(action)) {
const { queryCacheKey, requestId, options } = action.payload

if (mutableState?.[queryCacheKey]?.[requestId]) {
mutableState[queryCacheKey]![requestId] = options
}
return true
}
if (unsubscribeQueryResult.match(action)) {
const { queryCacheKey, requestId } = action.payload
if (mutableState[queryCacheKey]) {
delete mutableState[queryCacheKey]![requestId]
}
return true
}
if (api.internalActions.removeQueryResult.match(action)) {
delete mutableState[action.payload.queryCacheKey]
return true
}
if (queryThunk.pending.match(action)) {
const {
meta: { arg, requestId },
} = action
if (arg.subscribe) {
const substate = (mutableState[arg.queryCacheKey] ??= {})
substate[requestId] =
arg.subscriptionOptions ?? substate[requestId] ?? {}

return true
}
}
if (queryThunk.rejected.match(action)) {
const {
meta: { condition, arg, requestId },
} = action
if (condition && arg.subscribe) {
const substate = (mutableState[arg.queryCacheKey] ??= {})
substate[requestId] =
arg.subscriptionOptions ?? substate[requestId] ?? {}

return true
}
}

return false
}

return (action, mwApi) => {
if (!previousSubscriptions) {
// Initialize it the first time this handler runs
previousSubscriptions = JSON.parse(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,11 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
reducerPath,
api,
context,
internalState,
}) => {
const { removeQueryResult, unsubscribeQueryResult } = api.internalActions

function anySubscriptionsRemainingForKey(
queryCacheKey: string,
internalState: InternalMiddlewareState
) {
function anySubscriptionsRemainingForKey(queryCacheKey: string) {
const subscriptions = internalState.currentSubscriptions[queryCacheKey]
return !!subscriptions && !isObjectEmpty(subscriptions)
}
Expand All @@ -76,7 +74,6 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
queryCacheKey,
state.queries[queryCacheKey]?.endpointName,
mwApi,
internalState,
state.config
)
}
Expand All @@ -99,7 +96,6 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
queryCacheKey as QueryCacheKey,
queryState?.endpointName,
mwApi,
internalState,
state.config
)
}
Expand All @@ -110,7 +106,6 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
queryCacheKey: QueryCacheKey,
endpointName: string | undefined,
api: SubMiddlewareApi,
internalState: InternalMiddlewareState,
config: ConfigState<string>
) {
const endpointDefinition = context.endpointDefinitions[
Expand All @@ -132,13 +127,13 @@ export const buildCacheCollectionHandler: InternalHandlerBuilder = ({
Math.min(keepUnusedDataFor, THIRTY_TWO_BIT_MAX_TIMER_SECONDS)
)

if (!anySubscriptionsRemainingForKey(queryCacheKey, internalState)) {
if (!anySubscriptionsRemainingForKey(queryCacheKey)) {
const currentTimeout = currentRemovalTimeouts[queryCacheKey]
if (currentTimeout) {
clearTimeout(currentTimeout)
}
currentRemovalTimeouts[queryCacheKey] = setTimeout(() => {
if (!anySubscriptionsRemainingForKey(queryCacheKey, internalState)) {
if (!anySubscriptionsRemainingForKey(queryCacheKey)) {
api.dispatch(removeQueryResult({ queryCacheKey }))
}
delete currentRemovalTimeouts![queryCacheKey]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export const buildCacheLifecycleHandler: InternalHandlerBuilder = ({
context,
queryThunk,
mutationThunk,
internalState,
}) => {
const isQueryThunk = isAsyncThunkAction(queryThunk)
const isMutationThunk = isAsyncThunkAction(mutationThunk)
Expand All @@ -197,7 +198,6 @@ export const buildCacheLifecycleHandler: InternalHandlerBuilder = ({
const handler: ApiMiddlewareInternalHandler = (
action,
mwApi,
internalState,
stateBefore
) => {
const cacheKey = getCacheKey(action)
Expand Down
14 changes: 7 additions & 7 deletions packages/toolkit/src/query/core/buildMiddleware/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,17 @@ export function buildMiddleware<
> = (mwApi) => {
let initialized = false

let internalState: InternalMiddlewareState = {
currentSubscriptions: {},
}

const builderArgs = {
...(input as any as BuildMiddlewareInput<
EndpointDefinitions,
string,
string
>),
internalState,
refetchQuery,
}

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

let internalState: InternalMiddlewareState = {
currentSubscriptions: {},
}

return (next) => {
return (action) => {
if (!initialized) {
Expand All @@ -92,7 +93,6 @@ export function buildMiddleware<
const [actionShouldContinue, hasSubscription] = batchedActionsHandler(
action,
mwApiWithNext,
internalState,
stateBefore
)

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

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

if (
isThisApiSliceAction(action) ||
Expand All @@ -117,7 +117,7 @@ export function buildMiddleware<
// Only run these additional checks if the actions are part of the API slice,
// or the action has hydration-related data
for (let handler of handlers) {
handler(action, mwApiWithNext, internalState, stateBefore)
handler(action, mwApiWithNext, stateBefore)
}
}
}
Expand Down
21 changes: 8 additions & 13 deletions packages/toolkit/src/query/core/buildMiddleware/polling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,34 @@ export const buildPollingHandler: InternalHandlerBuilder = ({
queryThunk,
api,
refetchQuery,
internalState,
}) => {
const currentPolls: QueryStateMeta<{
nextPollTimestamp: number
timeout?: TimeoutId
pollingInterval: number
}> = {}

const handler: ApiMiddlewareInternalHandler = (
action,
mwApi,
internalState
) => {
const handler: ApiMiddlewareInternalHandler = (action, mwApi) => {
if (
api.internalActions.updateSubscriptionOptions.match(action) ||
api.internalActions.unsubscribeQueryResult.match(action)
) {
updatePollingInterval(action.payload, mwApi, internalState)
updatePollingInterval(action.payload, mwApi)
}

if (
queryThunk.pending.match(action) ||
(queryThunk.rejected.match(action) && action.meta.condition)
) {
updatePollingInterval(action.meta.arg, mwApi, internalState)
updatePollingInterval(action.meta.arg, mwApi)
}

if (
queryThunk.fulfilled.match(action) ||
(queryThunk.rejected.match(action) && !action.meta.condition)
) {
startNextPoll(action.meta.arg, mwApi, internalState)
startNextPoll(action.meta.arg, mwApi)
}

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

function startNextPoll(
{ queryCacheKey }: QuerySubstateIdentifier,
api: SubMiddlewareApi,
internalState: InternalMiddlewareState
api: SubMiddlewareApi
) {
const state = api.getState()[reducerPath]
const querySubState = state.queries[queryCacheKey]
Expand Down Expand Up @@ -90,8 +86,7 @@ export const buildPollingHandler: InternalHandlerBuilder = ({

function updatePollingInterval(
{ queryCacheKey }: QuerySubstateIdentifier,
api: SubMiddlewareApi,
internalState: InternalMiddlewareState
api: SubMiddlewareApi
) {
const state = api.getState()[reducerPath]
const querySubState = state.queries[queryCacheKey]
Expand All @@ -112,7 +107,7 @@ export const buildPollingHandler: InternalHandlerBuilder = ({
const nextPollTimestamp = Date.now() + lowestPollingInterval

if (!currentPoll || nextPollTimestamp < currentPoll.nextPollTimestamp) {
startNextPoll({ queryCacheKey }, api, internalState)
startNextPoll({ queryCacheKey }, api)
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/toolkit/src/query/core/buildMiddleware/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export type SubMiddlewareApi = MiddlewareAPI<

export interface BuildSubMiddlewareInput
extends BuildMiddlewareInput<EndpointDefinitions, string, string> {
internalState: InternalMiddlewareState
refetchQuery(
querySubState: Exclude<
QuerySubState<any>,
Expand All @@ -73,7 +74,6 @@ export type SubMiddlewareBuilder = (
export type ApiMiddlewareInternalHandler<ReturnType = void> = (
action: AnyAction,
mwApi: SubMiddlewareApi & { next: Dispatch<AnyAction> },
internalState: InternalMiddlewareState,
prevState: RootState<EndpointDefinitions, string, string>
) => ReturnType

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { onFocus, onOnline } from '../setupListeners'
import type {
ApiMiddlewareInternalHandler,
InternalHandlerBuilder,
InternalMiddlewareState,
SubMiddlewareApi,
} from './types'

Expand All @@ -13,26 +12,22 @@ export const buildWindowEventHandler: InternalHandlerBuilder = ({
context,
api,
refetchQuery,
internalState,
}) => {
const { removeQueryResult } = api.internalActions

const handler: ApiMiddlewareInternalHandler = (
action,
mwApi,
internalState
) => {
const handler: ApiMiddlewareInternalHandler = (action, mwApi) => {
if (onFocus.match(action)) {
refetchValidQueries(mwApi, 'refetchOnFocus', internalState)
refetchValidQueries(mwApi, 'refetchOnFocus')
}
if (onOnline.match(action)) {
refetchValidQueries(mwApi, 'refetchOnReconnect', internalState)
refetchValidQueries(mwApi, 'refetchOnReconnect')
}
}

function refetchValidQueries(
api: SubMiddlewareApi,
type: 'refetchOnFocus' | 'refetchOnReconnect',
internalState: InternalMiddlewareState
type: 'refetchOnFocus' | 'refetchOnReconnect'
) {
const state = api.getState()[reducerPath]
const queries = state.queries
Expand Down