Skip to content

Commit 9966480

Browse files
phryneasmarkerikson
authored andcommitted
document alternative callback-builder-style notation for actions… (#268)
* alternative callback-builder-style notation for actionsMap * Clarify builder usage purpose * Fix formatting and wording * Fix TS usage in createSlice example
1 parent 914e8bd commit 9966480

File tree

4 files changed

+51
-21
lines changed

4 files changed

+51
-21
lines changed

docs/api/createReducer.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,22 @@ const counterReducer = createReducer(0, {
4949
})
5050
```
5151

52+
### The "builder callback" API
53+
54+
Instead of using a simple object as an argument to `createReducer`, you can also provide a callback that receives an `ActionReducerMapBuilder` instance:
55+
56+
```typescript
57+
createReducer(0, builder =>
58+
builder.add(increment, (state, action) => {
59+
// action is inferred correctly here
60+
})
61+
)
62+
```
63+
64+
This is intended for use with TypeScript, as passing a plain object full of reducer functions cannot infer their types correctly in this case. It has no real benefit when used with plain JS.
65+
66+
We recommend using this API if stricter type safety is necessary when defining reducer argument objects.
67+
5268
## Direct State Mutation
5369

5470
Redux requires reducer functions to be pure and treat state values as immutable. While this is essential for making state updates predictable and observable, it can sometimes make the implementation of such updates awkward. Consider the following example:

docs/api/createSlice.md

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ function createSlice({
2323
// A name, used in action types
2424
name: string,
2525
// An additional object of "case reducers". Keys should be other action types.
26-
extraReducers?: Object<string, ReducerFunction>
26+
extraReducers?:
27+
| Object<string, ReducerFunction>
28+
| ((builder: ActionReducerMapBuilder<State>) => void)
2729
})
2830
```
2931

@@ -71,6 +73,12 @@ Action creators that were generated using [`createAction`](./createAction.md) ma
7173
computed property syntax. (If you are using TypeScript, you may have to use `actionCreator.type` or `actionCreator.toString()`
7274
to force the TS compiler to accept the computed property.)
7375

76+
### The "builder callback" API for `extraReducers`
77+
78+
Instead of using a simple object as `extraReducers`, you can also use a callback that receives a `ActionReducerMapBuilder` instance.
79+
80+
We recommend using this API if stricter type safety is necessary when defining reducer argument objects.
81+
7482
## Return Value
7583

7684
`createSlice` will return an object that looks like:
@@ -103,21 +111,28 @@ for references in a larger codebase.
103111

104112
## Examples
105113

106-
```js
107-
import { createSlice } from '@reduxjs/toolkit'
114+
```ts
115+
import { createSlice, createAction, PayloadAction } from '@reduxjs/toolkit'
108116
import { createStore, combineReducers } from 'redux'
109117
118+
const incrementBy = createAction<number>('incrementBy')
119+
110120
const counter = createSlice({
111121
name: 'counter',
112-
initialState: 0,
122+
initialState: 0 as number,
113123
reducers: {
114124
increment: state => state + 1,
115125
decrement: state => state - 1,
116126
multiply: {
117-
reducer: (state, action) => state * action.payload,
118-
prepare: value => ({ payload: value || 2 }) // fallback if the payload is a falsy value
127+
reducer: (state, action: PayloadAction<number>) => state * action.payload,
128+
prepare: (value: number) => ({ payload: value || 2 }) // fallback if the payload is a falsy value
119129
}
120-
}
130+
},
131+
// "builder callback API"
132+
extraReducers: builder =>
133+
builder.add(incrementBy, (state, action) => {
134+
return state + action.payload
135+
})
121136
})
122137
123138
const user = createSlice({
@@ -128,6 +143,7 @@ const user = createSlice({
128143
state.name = action.payload // mutate the state all you want with immer
129144
}
130145
},
146+
// "map object API"
131147
extraReducers: {
132148
[counter.actions.increment]: (state, action) => {
133149
state.age += 1

docs/usage/usage-with-typescript.md

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -142,19 +142,17 @@ As an alternative, RTK includes a type-safe reducer builder API.
142142
Instead of using a simple object as an argument to `createReducer`, you can also use a callback that receives a `ActionReducerMapBuilder` instance:
143143

144144
```typescript
145-
{
146-
const increment = createAction<number, 'increment'>('increment')
147-
const decrement = createAction<number, 'decrement'>('decrement')
148-
createReducer(0, builder =>
149-
builder
150-
.add(increment, (state, action) => {
151-
// action is inferred correctly here
152-
})
153-
.add(decrement, (state, action: PayloadAction<string>) => {
154-
// this would error out
155-
})
156-
)
157-
}
145+
const increment = createAction<number, 'increment'>('increment')
146+
const decrement = createAction<number, 'decrement'>('decrement')
147+
createReducer(0, builder =>
148+
builder
149+
.add(increment, (state, action) => {
150+
// action is inferred correctly here
151+
})
152+
.add(decrement, (state, action: PayloadAction<string>) => {
153+
// this would error out
154+
})
155+
)
158156
```
159157

160158
We recommend using this API if stricter type safety is necessary when defining reducer argument objects.

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)