Skip to content

Commit bbb0ea4

Browse files
committed
Merge branch 'master' of github.com:reduxjs/redux-starter-kit
2 parents 906d01d + f939388 commit bbb0ea4

File tree

3 files changed

+82
-27
lines changed

3 files changed

+82
-27
lines changed

docs/api/createAction.md

Lines changed: 78 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,44 +7,96 @@ hide_title: true
77

88
# `createAction`
99

10-
A utility function to create an action creator for the given action type string. The action creator accepts a single argument, which will be included in the action object as a field called `payload`. The action creator function will also have its `toString()` overriden so that it returns the action type, allowing it to be used in reducer logic that is looking for that action type.
10+
A helper function for defining a Redux [action](https://redux.js.org/basics/actions) type and creator.
1111

1212
```js
13-
// actions.js
14-
import { createAction } from 'redux-starter-kit'
15-
16-
export const increment = createAction('increment')
17-
18-
console.log(increment)
19-
// "increment"
13+
function createAction(type)
14+
```
2015

21-
const theAction = increment(5)
22-
console.log(theAction)
23-
// {type : "increment", payload : 5}
16+
The usual way to define an action in Redux is to separately declare an _action type_ constant and an _action creator_ function for constructing actions of that type.
2417

25-
// reducer.js
26-
import { increment } from './actions'
18+
```js
19+
const INCREMENT = 'counter/increment'
2720

28-
function counterReducer(state = 0, action) {
29-
switch (action.type) {
30-
// action creator's `toString()` can be used as the type for comparisons
31-
case increment.toString(): {
32-
return state + action.payload
33-
}
34-
default:
35-
return state
21+
function increment(amount) {
22+
return {
23+
type: INCREMENT,
24+
payload: amount
3625
}
3726
}
27+
28+
const action = increment(3)
29+
// { type: 'counter/increment', payload: 3 }
30+
```
31+
32+
The `createAction` helper combines these two declarations into one. It takes an action type and returns an action creator for that type. The action creator can be called either without arguments or with a `payload` to be attached to the action. Also, the action creator overrides [toString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString) so that the action type becomes its string representation.
33+
34+
```js
35+
const increment = createAction('counter/increment')
36+
37+
let action = increment()
38+
// { type: 'counter/increment' }
39+
40+
action = increment(3)
41+
// returns { type: 'counter/increment', payload: 3 }
42+
43+
increment.toString()
44+
// 'counter/increment'
45+
46+
`The action type is: ${increment}`
47+
// 'The action type is: counter/increment'
48+
```
49+
50+
## Usage with createReducer()
51+
52+
Because of their `toString()` override, action creators returned by `createAction()` can be used directly as keys for the case reducers passed to [createReducer()](createReducer.md).
53+
54+
```js
55+
const increment = createAction('counter/increment')
56+
const decrement = createAction('counter/decrement')
57+
58+
const counterReducer = createReducer(0, {
59+
[increment]: (state, action) => state + action.payload,
60+
[decrement]: (state, action) => state - action.payload
61+
})
62+
```
63+
64+
This works because object keys that are not natively supported by JavaScript (like, in this case, functions) are implicitly converted to strings, and the action creators’ string representations happen to be the action types they produce.
65+
66+
## Non-String Action Types
67+
68+
In principle, Redux lets you use any kind of value as an action type. Instead of strings, you could theoretically use numbers, [symbols](https://developer.mozilla.org/en-US/docs/Glossary/Symbol), or anything else ([although it's recommended that the value should at least be serializable](https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants)).
69+
70+
However, `redux-starter-kit` rests on the assumption that you use string action types. Specifically, some of its features rely on the fact that with strings, the `toString()` method of an `createAction()` action creator returns the matching action type. This is not the case for non-string action types because `toString()` will return the string-converted type value rather than the type itself.
71+
72+
```js
73+
const INCREMENT = Symbol('increment')
74+
const increment = createAction(INCREMENT)
75+
76+
increment.toString()
77+
// returns the string 'Symbol(increment)',
78+
// not the INCREMENT symbol itself
79+
80+
increment.toString() === INCREMENT
81+
// false
3882
```
3983

40-
Since action creators returned by `createAction` have `toString()` overridden, they can be used in `createReducer` as a key in the `actionsMap`:
84+
This means that, for instance, you cannot use a non-string-type action creator as a case reducer key for [createReducer()](createReducer.md).
4185

4286
```js
43-
// reducer.js
44-
import { createReducer } from 'redux-starter-kit'
45-
import { increment } from './actions'
87+
const INCREMENT = Symbol('increment')
88+
const increment = createAction(INCREMENT)
4689

4790
const counterReducer = createReducer(0, {
48-
[increment]: (state, action) => state + action.payload
91+
// The following case reducer will NOT trigger for
92+
// increment() actions because `increment` will be
93+
// interpreted as a string, rather than being evaluated
94+
// to the INCREMENT symbol.
95+
[increment]: (state, action) => state + action.payload,
96+
97+
// You would need to use the action type explicitly instead.
98+
[INCREMENT]: (state, action) => state + action.payload
4999
})
50100
```
101+
102+
For this reason, **we strongly recommend you to only use string action types**.

index.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ export {
66
Middleware,
77
Reducer,
88
Store,
9-
StoreEnhancer
9+
StoreEnhancer,
10+
combineReducers,
11+
compose
1012
} from 'redux'
1113
export { default as createSelector } from 'selectorator'
1214

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export { combineReducers, compose } from 'redux'
12
export { default as createNextState } from 'immer'
23
export { default as createSelector } from 'selectorator'
34

0 commit comments

Comments
 (0)