-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2401 from reduxjs/v1.9-integration
- Loading branch information
Showing
121 changed files
with
9,451 additions
and
4,086 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
**/dist/** | ||
**/etc/** | ||
**/temp/** | ||
**/temp/** | ||
**/__testfixtures__/** |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
diff --git a/lib/types/context/set.d.ts b/lib/types/context/set.d.ts | ||
index 266229bad706ec49392b8b87e18560c1566b490d..4fad485f8ffec2db92e808a05ccd9274414a9bd9 100644 | ||
--- a/lib/types/context/set.d.ts | ||
+++ b/lib/types/context/set.d.ts | ||
@@ -15,4 +15,5 @@ export declare type ForbiddenHeaderError<HeaderName extends string> = `SafeRespo | ||
* }) | ||
* @see {@link https://mswjs.io/docs/api/context/set `ctx.set()`} | ||
*/ | ||
+// @ts-ignore | ||
export declare function set<N extends string | HeadersObject>(...args: N extends string ? Lowercase<N> extends ForbiddenHeaderNames ? ForbiddenHeaderError<N> : [N, string] : N extends HeadersObject<infer CookieName> ? Lowercase<CookieName> extends ForbiddenHeaderNames ? ForbiddenHeaderError<CookieName> : [N] : [N]): ResponseTransformer; | ||
diff --git a/lib/types/sharedOptions.d.ts b/lib/types/sharedOptions.d.ts | ||
index d1d6e05df2dc2c29f06d8d0b91c500a10e651a29..3d8c29fd2089b2abf21d78cd277aac9271e781c2 100644 | ||
--- a/lib/types/sharedOptions.d.ts | ||
+++ b/lib/types/sharedOptions.d.ts | ||
@@ -21,4 +21,5 @@ export interface LifeCycleEventsMap<ResponseType> { | ||
'response:bypass': (response: ResponseType, requestId: string) => void; | ||
unhandledException: (error: Error, request: MockedRequest) => void; | ||
} | ||
+// @ts-ignore | ||
export declare type LifeCycleEventEmitter<ResponseType> = Pick<StrictEventEmitter<ResponseType>, 'on' | 'removeListener' | 'removeAllListeners'>; |
This file was deleted.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
--- | ||
id: autoBatchEnhancer | ||
title: autoBatchEnhancer | ||
sidebar_label: autoBatchEnhancer | ||
hide_title: true | ||
--- | ||
|
||
| ||
|
||
# `autoBatchEnhancer` | ||
|
||
A Redux store enhancer that looks for one or more "low-priority" dispatched actions in a row, and queues a callback to run subscriber notifications on a delay. It then notifies subscribers either when the queued callback runs, or when the next "normal-priority" action is dispatched, whichever is first. | ||
|
||
## Basic Usage | ||
|
||
```ts | ||
import { | ||
createSlice, | ||
configureStore, | ||
autoBatchEnhancer, | ||
prepareAutoBatched, | ||
} from '@reduxjs/toolkit' | ||
|
||
interface CounterState { | ||
value: number | ||
} | ||
|
||
const counterSlice = createSlice({ | ||
name: 'counter', | ||
initialState: { value: 0 } as CounterState, | ||
reducers: { | ||
incrementBatched: { | ||
// Batched, low-priority | ||
reducer(state) { | ||
state.value += 1 | ||
}, | ||
// highlight-start | ||
// Use the `prepareAutoBatched` utility to automatically | ||
// add the `action.meta[SHOULD_AUTOBATCH]` field the enhancer needs | ||
prepare: prepareAutoBatched<void>(), | ||
// highlight-end | ||
}, | ||
// Not batched, normal priority | ||
decrementUnbatched(state) { | ||
state.value -= 1 | ||
}, | ||
}, | ||
}) | ||
const { incrementBatched, decrementUnbatched } = counterSlice.actions | ||
|
||
const store = configureStore({ | ||
reducer: counterSlice.reducer, | ||
// highlight-start | ||
enhancers: (existingEnhancers) => { | ||
// Add the autobatch enhancer to the store setup | ||
return existingEnhancers.concat(autoBatchEnhancer()) | ||
}, | ||
// highlight-end | ||
}) | ||
``` | ||
|
||
## API | ||
|
||
### `autoBatchEnhancer` | ||
|
||
```ts title="autoBatchEnhancer signature" no-transpile | ||
export type SHOULD_AUTOBATCH = string | ||
type AutoBatchOptions = | ||
| { type: 'tick' } | ||
| { type: 'timer'; timeout: number } | ||
| { type: 'raf' } | ||
| { type: 'callback'; queueNotification: (notify: () => void) => void } | ||
|
||
export type autoBatchEnhancer = (options?: AutoBatchOptions) => StoreEnhancer | ||
``` | ||
Creates a new instance of the autobatch store enhancer. | ||
Any action that is tagged with `action.meta[SHOULD_AUTOBATCH] = true` will be treated as "low-priority", and a notification callback will be queued. The enhancer will delay notifying subscribers until either: | ||
- The queued callback runs and triggers the notifications | ||
- A "normal-priority" action (any action _without_ `action.meta[SHOULD_AUTOBATCH] = true`) is dispatched in the same tick | ||
`autoBatchEnhancer` accepts options to configure how the notification callback is queued: | ||
- `{type: 'raf'}`: queues using `requestAnimationFrame` (default) | ||
- `{type: 'tick'}: queues using `queueMicrotask` | ||
- `{type: 'timer, timeout: number}`: queues using `setTimeout` | ||
- `{type: 'callback', queueNotification: (notify: () => void) => void}: lets you provide your own callback, such as a debounced or throttled function | ||
The default behavior is to queue the notifications using `requestAnimationFrame`. | ||
The `SHOULD_AUTOBATCH` value is meant to be opaque - it's currently a string for simplicity, but could be a `Symbol` in the future. | ||
### `prepareAutoBatched` | ||
```ts title="prepareAutoBatched signature" no-transpile | ||
type prepareAutoBatched = <T>() => (payload: T) => { payload: T; meta: unknown } | ||
``` | ||
Creates a function that accepts a `payload` value, and returns an object with `{payload, meta: {[SHOULD_AUTOBATCH]: true}}`. This is meant to be used with RTK's `createSlice` and its "`prepare` callback" syntax: | ||
```ts no-transpile | ||
createSlice({ | ||
name: 'todos', | ||
initialState, | ||
reducers: { | ||
todoAdded: { | ||
reducer(state, action: PayloadAction<Todo>) { | ||
state.push(action.payload) | ||
}, | ||
// highlight-start | ||
prepare: prepareAutoBatched<Todo>(), | ||
// highlight-end | ||
}, | ||
}, | ||
}) | ||
``` | ||
## Batching Approach and Background | ||
The post [A Comparison of Redux Batching Techniques](https://blog.isquaredsoftware.com/2020/01/blogged-answers-redux-batching-techniques/) describes four different approaches for "batching Redux actions/dispatches" | ||
- a higher-order reducer that accepts multiple actions nested inside one real action, and iterates over them together | ||
- an enhancer that wraps `dispatch` and debounces the notification callback | ||
- an enhancer that wraps `dispatch` to accept an array of actions | ||
- React's `unstable_batchedUpdates()`, which just combines multiple queued renders into one but doesn't affect subscriber notifications | ||
This enhancer is a variation of the "debounce" approach, but with a twist. | ||
Instead of _just_ debouncing _all_ subscriber notifications, it watches for any actions with a specific `action.meta[SHOULD_AUTOBATCH]: true` field attached. | ||
When it sees an action with that field, it queues a callback. The reducer is updated immediately, but the enhancer does _not_ notify subscribers right way. If other actions with the same field are dispatched in succession, the enhancer will continue to _not_ notify subscribers. Then, when the queued callback runs, it finally notifies all subscribers, similar to how React batches re-renders. | ||
The additional twist is also inspired by React's separation of updates into "low-priority" and "immediate" behavior (such as a render queued by an AJAX request vs a render queued by a user input that should be handled synchronously). | ||
If some low-pri actions have been dispatched and a notification microtask is queued, then a _normal_ priority action (without the field) is dispatched, the enhancer will go ahead and notify all subscribers synchronously as usual, and _not_ notify them at the end of the tick. | ||
This allows Redux users to selectively tag certain actions for effective batching behavior, making this purely opt-in on a per-action basis, while retaining normal notification behavior for all other actions. | ||
### RTK Query and Batching | ||
RTK Query already marks several of its key internal action types as batchable. If you add the `autoBatchEnhancer` to the store setup, it will improve the overall UI performance, especially when rendering large lists of components that use the RTKQ query hooks. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
--- | ||
id: codemods | ||
title: Codemods | ||
sidebar_label: Codemods | ||
hide_title: true | ||
--- | ||
|
||
| ||
|
||
# Codemods | ||
|
||
Per [the description in `1.9.0-alpha.0`](https://github.com/reduxjs/redux-toolkit/releases/tag/v1.9.0-alpha.0), we plan to remove the "object" argument from `createReducer` and `createSlice.extraReducers` in the future RTK 2.0 major version. In `1.9.0-alpha.0`, we added a one-shot runtime warning to each of those APIs. | ||
|
||
To simplify upgrading codebases, we've published a set of codemods that will automatically transform the deprecated "object" syntax into the equivalent "builder" syntax. | ||
|
||
The codemods package is available on NPM as [**`@reduxjs/rtk-codemods`**](https://www.npmjs.com/package/@reduxjs/rtk-codemods). It currently contains two codemods: `createReducerBuilder` and `createSliceBuilder`. | ||
|
||
To run the codemods against your codebase, run `npx @reduxjs/rtk-codemods <TRANSFORM NAME> path/of/files/ or/some**/*glob.js`. | ||
|
||
Examples: | ||
|
||
```bash | ||
npx @reduxjs/rtk-codemods createReducerBuilder ./src | ||
|
||
npx @reduxjs/rtk-codemods createSliceBuilder ./packages/my-app/**/*.ts | ||
``` | ||
|
||
We also recommend re-running Prettier on the codebase before committing the changes. | ||
|
||
**These codemods _should_ work, but we would greatly appreciate testing and feedback on more real-world codebases!** | ||
|
||
Before: | ||
|
||
```js | ||
createReducer(initialState, { | ||
[todoAdded1a]: (state, action) => { | ||
// stuff | ||
}, | ||
[todoAdded1b]: (state, action) => action.payload, | ||
}) | ||
|
||
const slice1 = createSlice({ | ||
name: 'a', | ||
initialState: {}, | ||
extraReducers: { | ||
[todoAdded1a]: (state, action) => { | ||
// stuff | ||
}, | ||
[todoAdded1b]: (state, action) => action.payload, | ||
}, | ||
}) | ||
``` | ||
|
||
After: | ||
|
||
```js | ||
createReducer(initialState, (builder) => { | ||
builder.addCase(todoAdded1a, (state, action) => { | ||
// stuff | ||
}) | ||
|
||
builder.addCase(todoAdded1b, (state, action) => action.payload) | ||
}) | ||
|
||
const slice1 = createSlice({ | ||
name: 'a', | ||
initialState: {}, | ||
|
||
extraReducers: (builder) => { | ||
builder.addCase(todoAdded1a, (state, action) => { | ||
// stuff | ||
}) | ||
|
||
builder.addCase(todoAdded1b, (state, action) => action.payload) | ||
}, | ||
}) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.