Skip to content

Commit

Permalink
document alternative callback-builder-style notation for actions… (re…
Browse files Browse the repository at this point in the history
…duxjs#268)

* alternative callback-builder-style notation for actionsMap

* Clarify builder usage purpose

* Fix formatting and wording

* Fix TS usage in createSlice example
  • Loading branch information
phryneas authored and markerikson committed Dec 1, 2019
1 parent 914e8bd commit 9966480
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 21 deletions.
16 changes: 16 additions & 0 deletions docs/api/createReducer.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@ const counterReducer = createReducer(0, {
})
```

### The "builder callback" API

Instead of using a simple object as an argument to `createReducer`, you can also provide a callback that receives an `ActionReducerMapBuilder` instance:

```typescript
createReducer(0, builder =>
builder.add(increment, (state, action) => {
// action is inferred correctly here
})
)
```

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.

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

## Direct State Mutation

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:
Expand Down
30 changes: 23 additions & 7 deletions docs/api/createSlice.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ function createSlice({
// A name, used in action types
name: string,
// An additional object of "case reducers". Keys should be other action types.
extraReducers?: Object<string, ReducerFunction>
extraReducers?:
| Object<string, ReducerFunction>
| ((builder: ActionReducerMapBuilder<State>) => void)
})
```

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

### The "builder callback" API for `extraReducers`

Instead of using a simple object as `extraReducers`, you can also use a callback that receives a `ActionReducerMapBuilder` instance.

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

## Return Value

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

## Examples

```js
import { createSlice } from '@reduxjs/toolkit'
```ts
import { createSlice, createAction, PayloadAction } from '@reduxjs/toolkit'
import { createStore, combineReducers } from 'redux'
const incrementBy = createAction<number>('incrementBy')
const counter = createSlice({
name: 'counter',
initialState: 0,
initialState: 0 as number,
reducers: {
increment: state => state + 1,
decrement: state => state - 1,
multiply: {
reducer: (state, action) => state * action.payload,
prepare: value => ({ payload: value || 2 }) // fallback if the payload is a falsy value
reducer: (state, action: PayloadAction<number>) => state * action.payload,
prepare: (value: number) => ({ payload: value || 2 }) // fallback if the payload is a falsy value
}
}
},
// "builder callback API"
extraReducers: builder =>
builder.add(incrementBy, (state, action) => {
return state + action.payload
})
})
const user = createSlice({
Expand All @@ -128,6 +143,7 @@ const user = createSlice({
state.name = action.payload // mutate the state all you want with immer
}
},
// "map object API"
extraReducers: {
[counter.actions.increment]: (state, action) => {
state.age += 1
Expand Down
24 changes: 11 additions & 13 deletions docs/usage/usage-with-typescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,17 @@ As an alternative, RTK includes a type-safe reducer builder API.
Instead of using a simple object as an argument to `createReducer`, you can also use a callback that receives a `ActionReducerMapBuilder` instance:

```typescript
{
const increment = createAction<number, 'increment'>('increment')
const decrement = createAction<number, 'decrement'>('decrement')
createReducer(0, builder =>
builder
.add(increment, (state, action) => {
// action is inferred correctly here
})
.add(decrement, (state, action: PayloadAction<string>) => {
// this would error out
})
)
}
const increment = createAction<number, 'increment'>('increment')
const decrement = createAction<number, 'decrement'>('decrement')
createReducer(0, builder =>
builder
.add(increment, (state, action) => {
// action is inferred correctly here
})
.add(decrement, (state, action: PayloadAction<string>) => {
// this would error out
})
)
```

We recommend using this API if stricter type safety is necessary when defining reducer argument objects.
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9966480

Please sign in to comment.