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

document alternative callback-builder-style notation for actions… #268

Merged
merged 4 commits into from
Dec 1, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
20 changes: 18 additions & 2 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 @@ -107,6 +115,8 @@ for references in a larger codebase.
import { createSlice } from '@reduxjs/toolkit'
import { createStore, combineReducers } from 'redux'

const incrementBy = createAction < number > 'incrementBy'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ummmh... wtf is prettier doing here...?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@markerikson I can't convince prettier of const incrementBy = createAction<number>('incrementBy') here...
Do you face the same problem?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code block is marked as js, not ts, so it's being mis-formatted.

And given that we aren't using any other TS in there, the example is kinda inconsistent anyway.


const counter = createSlice({
name: 'counter',
initialState: 0,
Expand All @@ -117,7 +127,12 @@ const counter = createSlice({
reducer: (state, action) => state * action.payload,
prepare: value => ({ 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.