Skip to content

Commit 36e15d4

Browse files
committed
Merge branches 'master', 'master' and 'feature/4252-entity-adapter-sorting' of https://github.com/reduxjs/redux-toolkit into feature/4252-entity-adapter-sorting
2 parents d0b3ba5 + e46eb99 commit 36e15d4

File tree

4 files changed

+132
-87
lines changed

4 files changed

+132
-87
lines changed

docs/rtk-query/internal/buildMiddleware/invalidationByTags.mdx

+28-23
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# invalidationByTags
22

3-
43
## Overview
4+
55
`InvalidationByTagsHandler` is a handler instantiated during the (BuildMiddleware) step of the build. The handler acts as a (Middleware) and executes each step in response to matching of internal asyncThunk actions.
66

77
The matchers used for a "invalidation sequence" are these two cases:
8+
89
```ts no-transpile
910
const isThunkActionWithTags = isAnyOf(
1011
isFulfilled(mutationThunk),
@@ -21,11 +22,12 @@ const isQueryEnd = isAnyOf(
2122

2223
The handler has 3 core conditionals that trigger a sequence:
2324

24-
*Conditional 1 AND 3 are identical in process except the tags are calculated from the payload rather than from the action and endpointDefinition*
25+
_Conditional 1 AND 3 are identical in process except the tags are calculated from the payload rather than from the action and endpointDefinition_
2526

2627
1. Mutation trigger
2728
2. Query trigger
2829
3. Manual invalidation via `api.util.invalidateTags` trigger
30+
2931
```ts no-transpile
3032
const handler: ApiMiddlewareInternalHandler = (action, mwApi) => {
3133
if (isThunkActionWithTags(action)) {
@@ -56,38 +58,40 @@ const handler: ApiMiddlewareInternalHandler = (action, mwApi) => {
5658
}
5759
```
5860

59-
6061
## Core Sequence
62+
6163
1. `invalidateTags()` initiates:
62-
1. invalidateTags function is called with a list of tags generated from the action metadata
63-
2. in the case of a [queryThunk] resolution an empty set of tags is always provided
64-
2. The tags calculated are added to the list of pending tags to invalidate (see [delayed](Delayed) )
64+
1. invalidateTags function is called with a list of tags generated from the action metadata
65+
2. in the case of a [queryThunk] resolution an empty set of tags is always provided
66+
2. The tags calculated are added to the list of pending tags to invalidate (see [delayed](#Delayed))
6567
3. (optional: 'Delayed') the invalidateTags function is ended if the `apiSlice.invalidationBehaviour` is set to "delayed" and there are any pending thunks/queries running in that `apiSlice`
6668
4. Pending tags are reset to an empty list, if there are no tags the function ends here
6769
5. Selects all `{ endpointName, originalArgs, queryCacheKey }` combinations that would be invalidated by a specific set of tags.
68-
6. Iterates through queryCacheKeys selected and performs one of two actions if the query exists*
69-
1. removes cached query result - via the `removeQueryResult` action - if no subscription is active
70-
2. if the query is "uninitialized" it initiates a `refetchQuery` action
70+
6. Iterates through queryCacheKeys selected and performs one of two actions if the query exists\*
71+
1. removes cached query result - via the `removeQueryResult` action - if no subscription is active
72+
2. if the query is "uninitialized" it initiates a `refetchQuery` action
73+
7174
```js no-transpile
72-
const toInvalidate = api.util.selectInvalidatedBy(rootState, tags);
75+
const toInvalidate = api.util.selectInvalidatedBy(rootState, tags)
7376
context.batch(() => {
74-
const valuesArray = Array.from(toInvalidate.values());
75-
for (const {
76-
queryCacheKey
77-
} of valuesArray) {
78-
const querySubState = state.queries[queryCacheKey];
79-
const subscriptionSubState = internalState.currentSubscriptions[queryCacheKey] ?? {};
77+
const valuesArray = Array.from(toInvalidate.values())
78+
for (const { queryCacheKey } of valuesArray) {
79+
const querySubState = state.queries[queryCacheKey]
80+
const subscriptionSubState =
81+
internalState.currentSubscriptions[queryCacheKey] ?? {}
8082
if (querySubState) {
8183
if (countObjectKeys(subscriptionSubState) === 0) {
82-
mwApi.dispatch(removeQueryResult({
83-
queryCacheKey
84-
}));
85-
} else if (querySubState.status !== "uninitialized" /* uninitialized */) {
86-
mwApi.dispatch(refetchQuery(querySubState, queryCacheKey));
84+
mwApi.dispatch(
85+
removeQueryResult({
86+
queryCacheKey,
87+
}),
88+
)
89+
} else if (querySubState.status !== 'uninitialized' /* uninitialized */) {
90+
mwApi.dispatch(refetchQuery(querySubState, queryCacheKey))
8791
}
8892
}
8993
}
90-
});
94+
})
9195
```
9296
9397
:::note
@@ -99,6 +103,7 @@ Step 6 is performed within a `context.batch()` call.
99103
RTKQ now has internal logic to delay tag invalidation briefly, to allow multiple invalidations to get handled together. This is controlled by a new `invalidationBehavior: 'immediate' | 'delayed'` flag on `createApi`. The new default behavior is `'delayed'`. Set it to `'immediate'` to revert to the behavior in RTK 1.9.
100104
101105
The `'delayed'` behaviour enables a check inside `invalidationByTags` that will cause any invalidation that is triggered while a query/mutation is still pending to batch the invalidation until no query/mutation is running.
106+
102107
```ts no-transpile
103108
function invalidateTags(
104109
newTags: readonly FullTagDescription<string>[],
@@ -115,4 +120,4 @@ function invalidateTags(
115120
) {
116121
return
117122
}
118-
```
123+
```

docs/rtk-query/internal/buildSlice.mdx

+72-55
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,41 @@
33
## Slices
44

55
### querySlice
6+
67
#### reducers
7-
- `removeQueryResult` - delete a specific cacheKey's stored result
8-
- `queryResultPatched` - patch a specific cacheKey's result
8+
9+
- `removeQueryResult` - delete a specific cacheKey's stored result
10+
- `queryResultPatched` - patch a specific cacheKey's result
11+
912
#### extraReducers - matching queryThunk cases
13+
1014
- `queryThunk.pending`
11-
- Initially sets QueryStatus to uninitialized
12-
- updates QueryStatus to pending
13-
- Generates requestId
14-
- stores originalArgs
15-
- stores startedTimeStamp
15+
- Initially sets QueryStatus to uninitialized
16+
- updates QueryStatus to pending
17+
- Generates requestId
18+
- stores originalArgs
19+
- stores startedTimeStamp
1620
- `queryThunk.fulfilled`
17-
- handles merge functionality first
18-
- otherwise updates the cache data, creates a fulfilledTimeStamp and deletes the substates error
21+
- handles merge functionality first
22+
- otherwise updates the cache data, creates a fulfilledTimeStamp and deletes the substates error
1923

2024
```ts no-transpile
2125
if (merge) {
2226
if (substate.data !== undefined) {
23-
const { fulfilledTimeStamp, arg, baseQueryMeta, requestId } =
24-
meta
27+
const { fulfilledTimeStamp, arg, baseQueryMeta, requestId } = meta
2528
// There's existing cache data. Let the user merge it in themselves.
2629
// We're already inside an Immer-powered reducer, and the user could just mutate `substate.data`
2730
// themselves inside of `merge()`. But, they might also want to return a new value.
2831
// Try to let Immer figure that part out, save the result, and assign it to `substate.data`.
29-
let newData = createNextState(
30-
substate.data,
31-
(draftSubstateData) => {
32-
// As usual with Immer, you can mutate _or_ return inside here, but not both
33-
return merge(draftSubstateData, payload, {
34-
arg: arg.originalArgs,
35-
baseQueryMeta,
36-
fulfilledTimeStamp,
37-
requestId,
38-
})
39-
},
40-
)
32+
let newData = createNextState(substate.data, (draftSubstateData) => {
33+
// As usual with Immer, you can mutate _or_ return inside here, but not both
34+
return merge(draftSubstateData, payload, {
35+
arg: arg.originalArgs,
36+
baseQueryMeta,
37+
fulfilledTimeStamp,
38+
requestId,
39+
})
40+
})
4141
substate.data = newData
4242
} else {
4343
// Presumably a fresh request. Just cache the response data.
@@ -47,85 +47,102 @@ let newData = createNextState(
4747
```
4848

4949
- `queryThunk.rejected`
50-
- utilises `condition()` from `queryThunk` and does nothing if the rejection is a result of `condition()` (indicates a thunk is already running here)
51-
- else substate.error is set and the status is changed to rejected
50+
- utilises `condition()` from `queryThunk` and does nothing if the rejection is a result of `condition()` (indicates a thunk is already running here)
51+
- else substate.error is set and the status is changed to rejected
5252
- `hasRehydrationInfo`
53-
- iterates through and resets entries for all fulfilled or rejected status
53+
- iterates through and resets entries for all fulfilled or rejected status
5454

5555
### mutationSlice
56+
5657
#### reducers
58+
5759
- `removeMutationResult`
58-
- calls `getMutationCacheKey` from payload
59-
- if cacheKey is in draft it deletes `draft[cacheKey`(?)
60+
- calls `getMutationCacheKey` from payload
61+
- if cacheKey is in draft it deletes `draft[cacheKey`(?)
62+
6063
#### extraReducers - matching mutationThunk cases
64+
6165
- `mutationThunk.pending`
62-
- exits if track is set to false
63-
- otherwise updates appropriate cacheKey with requestId, pending status and startedTimeStamp
66+
- exits if track is set to false
67+
- otherwise updates appropriate cacheKey with requestId, pending status and startedTimeStamp
6468
- `mutationThunk.fulfilled`
65-
- exits if track is set to false
66-
- otherwise sets data off payload and fulfilledTimeStamp
69+
- exits if track is set to false
70+
- otherwise sets data off payload and fulfilledTimeStamp
6771
- `mutationThunk.rejected`
68-
- exits if track is set to false
69-
- otherwise sets error and status to rejected
72+
- exits if track is set to false
73+
- otherwise sets error and status to rejected
7074
- `hasRehydrationInfo`
71-
- iterates through and resets entries for all fulfilled or rejected status
75+
- iterates through and resets entries for all fulfilled or rejected status
7276

7377
### invalidationSlice
7478

7579
#### reducers
80+
7681
- updateProvidedBy
77-
- takes queryCacheKey and providedTags from payload
78-
- appends to a list of idSubscriptions the queryCacheKey that are currently subscribed to for each tag
82+
- takes queryCacheKey and providedTags from payload
83+
- appends to a list of idSubscriptions the queryCacheKey that are currently subscribed to for each tag
84+
7985
#### extraReducers
86+
8087
- `querySlice.actions.removeQueryResult`,
81-
- deletes relevant queryCacheKey entry from list of subscription ids
88+
- deletes relevant queryCacheKey entry from list of subscription ids
8289
- `hasRehydrationInfo`
83-
- TODO
90+
- TODO
8491
- `queryThunk.fulfilled` or `queryThunk.rejected`
85-
- gets list of tags from action and endpoint definition
86-
- gets queryCacheKey
87-
- calls updateProvidedBy action
92+
- gets list of tags from action and endpoint definition
93+
- gets queryCacheKey
94+
- calls updateProvidedBy action
8895

8996
### subscriptionSlice / internalSubscriptionSlice
97+
9098
#### reducers
99+
91100
- updateSubscriptionOptions
92101
- unsubscribeQueryResult
93102
- internal_getRTKQSubscriptions
94103
- subscriptionsUpdated
95-
- applyPatches() to the state from the payload
104+
- applyPatches() to the state from the payload
96105

97106
### configSlice
107+
98108
#### reducers
109+
99110
- middlewareRegistered
100-
- toggles whether the middleware is registered or if there is a conflict
111+
- toggles whether the middleware is registered or if there is a conflict
112+
101113
#### extraReducers
114+
102115
- `onOnline`
103-
- manages state.online in response to listenerMiddleware
116+
- manages state.online in response to listenerMiddleware
104117
- `onOffline`
105-
- manages state.online in response to listenerMiddleware
118+
- manages state.online in response to listenerMiddleware
106119
- `onFocus`
107-
- manages state.focused in response to listenerMiddleware
120+
- manages state.focused in response to listenerMiddleware
108121
- `onFocusLost`
109-
- manages state.focused in response to listenerMiddleware
122+
- manages state.focused in response to listenerMiddleware
110123
- `hasRehydrationInfo`
111-
- lists a comment that says: "update the state to be a new object to be picked up as a "state change" by redux-persist's `autoMergeLevel2`"
112-
124+
- lists a comment that says: "update the state to be a new object to be picked up as a "state change" by redux-persist's `autoMergeLevel2`"
113125

114126
## Functions
127+
115128
### `updateQuerySubstateIfExists`
129+
116130
Utility function that takes the api/endpoint state, queryCacheKey and Update function.
117131
The "SubState" is determined by accessing the `queryCacheKey` value inside the state. If the substate exists, the update function is executed on the substate.
132+
118133
```js no-transpile
119134
function updateQuerySubstateIfExists(state, queryCacheKey, update) {
120-
const substate = state[queryCacheKey];
135+
const substate = state[queryCacheKey]
121136
if (substate) {
122-
update(substate);
137+
update(substate)
123138
}
124139
}
125140
```
126141

127142
### `getMutationCacheKey`
143+
128144
conditionally determines the cachekey to be used for the mutation, prioritising the argument provided, followed by the provided cacheKey, and the generated requestId otherwise
145+
129146
```ts no-transpile
130147
export function getMutationCacheKey(
131148
id:
@@ -140,12 +157,12 @@ export function getMutationCacheKey(
140157
### `getMutationSubstateIfExists`
141158

142159
same as query version except it uses the id instead of the queryCacheKey, and uses the `getMutationCacheKey` to determine the cachekey
160+
143161
```js no-transpile
144162
function updateMutationSubstateIfExists(state, id, update) {
145-
const substate = state[getMutationCacheKey(id)];
163+
const substate = state[getMutationCacheKey(id)]
146164
if (substate) {
147-
update(substate);
165+
update(substate)
148166
}
149167
}
150168
```
151-

docs/rtk-query/internal/overview.mdx

+9-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
This documentation is intended to provide a high-level overview of the internal architecture of RTK-Query. It is not intended to be a comprehensive guide to the library, but rather a guide to the internal architecture and how it works.
88

99
## createApi - The Entry Point
10+
1011
When `createApi()` is called it takes the options provided and calls internally the `buildCreateApi()` function passing into it two modules:
1112

12-
*Modules are RTK-Query's method of customizing how the `createApi` method handles endpoints.*
13+
_Modules are RTK-Query's method of customizing how the `createApi` method handles endpoints._
1314

1415
- `coreModule()` - responsible for the majority of the internal handling using core redux logic i.e. slices, reducers, asyncThunks.
1516
- `reactHooksModule()` - a module that generates react hooks from endpoints using react-redux
@@ -19,6 +20,7 @@ When `createApi()` is called it takes the options provided and calls internally
1920
The core module takes the `api` and the options passed to `createApi()`. In turn an internal set of "build" methods are called. Each of these build methods create a set of functions which are assigned to either `api.util` or `api.internalActions` and/or passed to a future "build" step.
2021

2122
### buildThunks
23+
2224
RTK-Query's internal functionality operates using the same `asyncThunk` exposed from RTK. In the first "build" method, a number of thunks are generated for the core module to use:
2325

2426
- `queryThunk`
@@ -30,10 +32,12 @@ RTK-Query's internal functionality operates using the same `asyncThunk` exposed
3032
- `buildMatchThunkActions`
3133

3234
### buildSlice
35+
3336
RTK-Query uses a very familiar redux-centric architecture. Where the `api` is a slice of your store, the `api` has its own slices created within it. These slices are where the majority of the RTKQ magic happens.
3437

3538
The slices built inside this "build" are:
36-
*Some of which have their own actions*
39+
_Some of which have their own actions_
40+
3741
- querySlice
3842
- mutationSlice
3943
- invalidationSlice
@@ -44,6 +48,7 @@ The slices built inside this "build" are:
4448
buildSlice also exposes the core action `resetApiState` which is subsequently added to the `api.util`
4549

4650
### buildMiddleware
51+
4752
RTK-Query has a series of custom middlewares established within its store to handle additional responses in addition to the core logic established within the slices from buildSlice.
4853

4954
Each middleware built during this step is referred to internally as a "Handler" and are as follows:
@@ -56,6 +61,7 @@ Each middleware built during this step is referred to internally as a "Handler"
5661
- `buildQueryLifecycleHandler
5762

5863
### buildSelectors
64+
5965
build selectors is a crucial step that exposes to the `api` and utils:
6066

6167
- `buildQuerySelector
@@ -64,4 +70,5 @@ build selectors is a crucial step that exposes to the `api` and utils:
6470
- `selectCachedArgsForQuery
6571

6672
### return
73+
6774
Finally each endpoint passed into the `createApi()` is iterated over and assigned either the query or the mutation selectors, initiators and match cases.

0 commit comments

Comments
 (0)