Skip to content

Commit db563d7

Browse files
author
keenondrums
committed
Add function-based action creator support
1 parent 9efcdc3 commit db563d7

File tree

5 files changed

+331
-57
lines changed

5 files changed

+331
-57
lines changed

README.md

Lines changed: 154 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,10 @@ Consider using it with [flux-action-class](https://github.com/keenondrums/flux-a
1313
- [Angular](#angular)
1414
- [React](#react)
1515
- [Quick start](#quick-start)
16-
- [Recommended](#recommended)
16+
- [Recommended (with flux-action-class)](#recommended-with-flux-action-class)
1717
- [Classic NGRX actions](#classic-ngrx-actions)
18+
- [With redux-actions](#with-redux-actions)
1819
- [Old school: action type constants](#old-school-action-type-constants)
19-
- [JavaScript with flux-action-class](#javascript-with-flux-action-class)
20-
- [Old school: JavaScript](#old-school-javascript)
2120
- [Integration with `immer`](#integration-with-immer)
2221
- [In depth](#in-depth)
2322
- [When we can we omit list of actions for `@Action`?](#when-we-can-we-omit-list-of-actions-for-action)
@@ -41,7 +40,7 @@ Consider using it with [flux-action-class](https://github.com/keenondrums/flux-a
4140
"emitDecoratorMetadata": true,
4241
```
4342

44-
1. If you use JavaScript configure your babel to support decorators
43+
1. If you use JavaScript configure your babel to support decorators and class properties
4544

4645
### React
4746

@@ -60,11 +59,11 @@ Consider using it with [flux-action-class](https://github.com/keenondrums/flux-a
6059
"emitDecoratorMetadata": true,
6160
```
6261

63-
1. If you use JavaScript configure your babel to support decorators
62+
1. If you use JavaScript configure your babel to support decorators and class properties
6463

6564
## Quick start
6665

67-
### Recommended
66+
### Recommended (with [flux-action-class](https://github.com/keenondrums/flux-action-class))
6867

6968
```ts
7069
import { ActionStandard } from 'flux-action-class'
@@ -100,6 +99,44 @@ class ReducerCat extends ReducerClass<IReducerCatState> {
10099
const reducer = ReducerCat.create()
101100
```
102101

102+
<details>
103+
<summary>JavaScript version</summary>
104+
105+
```js
106+
import { ActionStandard } from 'flux-action-class'
107+
import { Action, ReducerClass } from 'reducer-class'
108+
109+
class ActionCatEat extends ActionStandard {}
110+
class ActionCatPlay extends ActionStandard {}
111+
class ActionCatBeAwesome extends ActionStandard {}
112+
113+
class ReducerCat extends ReducerClass {
114+
initialState = {
115+
energy: 100,
116+
}
117+
118+
@Action(ActionCatEat)
119+
addEnergy(state, action) {
120+
return {
121+
energy: state.energy + action.payload,
122+
}
123+
}
124+
125+
@Action(ActionCatPlay, ActionCatBeAwesome)
126+
wasteEnegry(state, action) {
127+
return {
128+
energy: state.energy - action.payload,
129+
}
130+
}
131+
}
132+
133+
const reducer = ReducerCat.create()
134+
```
135+
136+
> We can not use `Action` without arguments in JavaScript because there's no compiler which provides us with metadata for type reflection.
137+
138+
</details>
139+
103140
### Classic NGRX actions
104141

105142
```ts
@@ -144,14 +181,67 @@ class ReducerCat extends ReducerClass<IReducerCatState> {
144181
const reducer = ReducerCat.create()
145182
```
146183

147-
### Old school: action type constants
184+
<details>
185+
<summary>JavaScript version</summary>
186+
187+
```js
188+
import { Action, ReducerClass } from 'reducer-class'
189+
190+
class ActionCatEat {
191+
type = 'ActionCatEat'
192+
constructor(payload) {
193+
this.payload = payload
194+
}
195+
}
196+
class ActionCatPlay {
197+
type = 'ActionCatPlay'
198+
constructor(payload) {
199+
this.payload = payload
200+
}
201+
}
202+
class ActionCatBeAwesome {
203+
type = 'ActionCatBeAwesome'
204+
constructor(payload) {
205+
this.payload = payload
206+
}
207+
}
208+
209+
class ReducerCat extends ReducerClass {
210+
initialState = {
211+
energy: 100,
212+
}
213+
214+
@Action(ActionCatEat)
215+
addEnergy(state, action) {
216+
return {
217+
energy: state.energy + action.payload,
218+
}
219+
}
220+
221+
@Action(ActionCatPlay, ActionCatBeAwesome)
222+
wasteEnegry(state, action) {
223+
return {
224+
energy: state.energy - action.payload,
225+
}
226+
}
227+
}
228+
229+
const reducer = ReducerCat.create()
230+
```
231+
232+
> We can not use `Action` without arguments in JavaScript because there's no compiler which provides us with metadata for type reflection.
233+
234+
</details>
235+
236+
### With [redux-actions](https://github.com/redux-utilities/redux-actions)
148237

149238
```ts
150239
import { Action, ReducerClass } from 'reducer-class'
240+
import { createAction } from 'redux-actions'
151241

152-
const actionTypeCatEat = 'actionTypeCatEat'
153-
const actionTypeCatPlay = 'actionTypeCatPlay'
154-
const actionTypeCatBeAwesome = 'actionTypeCatBeAwesome'
242+
const actionCatEat = createAction('actionTypeCatEat')
243+
const actionCatPlay = createAction('actionTypeCatPlay')
244+
const actionCatBeAwesome = createAction('actionTypeCatBeAwesome')
155245

156246
interface IReducerCatState {
157247
energy: number
@@ -161,14 +251,14 @@ class ReducerCat extends ReducerClass<IReducerCatState> {
161251
energy: 100,
162252
}
163253

164-
@Action(actionTypeCatEat)
254+
@Action(actionCatEat)
165255
addEnergy(state: IReducerCatState, action: { payload: number }) {
166256
return {
167257
energy: state.energy + action.payload,
168258
}
169259
}
170260

171-
@Action(actionTypeCatPlay, actionTypeCatBeAwesome)
261+
@Action(actionCatPlay, actionCatBeAwesome)
172262
wasteEnegry(state: IReducerCatState, action: { payload: number }) {
173263
return {
174264
energy: state.energy - action.payload,
@@ -181,30 +271,31 @@ const reducer = ReducerCat.create()
181271

182272
> You might have noticed that we always pass actions to `Action` in this version. It's because we no longer use classes for our actions and TypeScript can not provide type metadata.
183273
184-
### JavaScript with flux-action-class
274+
<details>
275+
<summary>JavaScript version</summary>
185276

186277
```js
187-
import { ActionStandard } from 'flux-action-class'
188278
import { Action, ReducerClass } from 'reducer-class'
279+
import { createAction } from 'redux-actions'
189280

190-
class ActionCatEat {}
191-
class ActionCatPlay {}
192-
class ActionCatBeAwesome {}
281+
const actionCatEat = createAction('actionTypeCatEat')
282+
const actionCatPlay = createAction('actionTypeCatPlay')
283+
const actionCatBeAwesome = createAction('actionTypeCatBeAwesome')
193284

194285
class ReducerCat extends ReducerClass {
195286
initialState = {
196287
energy: 100,
197288
}
198289

199-
@Action(ActionCatEat)
200-
addEnergy(state, action) {
290+
@Action(actionCatEat)
291+
addEnergy(state, action: { payload }) {
201292
return {
202293
energy: state.energy + action.payload,
203294
}
204295
}
205296

206-
@Action(ActionCatPlay, ActionCatBeAwesome)
207-
wasteEnegry(state, action) {
297+
@Action(actionCatPlay, actionCatBeAwesome)
298+
wasteEnegry(state, action: { payload }) {
208299
return {
209300
energy: state.energy - action.payload,
210301
}
@@ -214,11 +305,47 @@ class ReducerCat extends ReducerClass {
214305
const reducer = ReducerCat.create()
215306
```
216307

217-
> We can not use `Action` without arguments in JavaScript because there's no compiler which provides us with metadata for type reflection.
308+
</details>
309+
310+
### Old school: action type constants
311+
312+
```ts
313+
import { Action, ReducerClass } from 'reducer-class'
314+
315+
const actionTypeCatEat = 'actionTypeCatEat'
316+
const actionTypeCatPlay = 'actionTypeCatPlay'
317+
const actionTypeCatBeAwesome = 'actionTypeCatBeAwesome'
218318

219-
> Be aware, you have to configure [babel](https://babeljs.io/) to provide you with decorator syntax.
319+
interface IReducerCatState {
320+
energy: number
321+
}
322+
class ReducerCat extends ReducerClass<IReducerCatState> {
323+
initialState = {
324+
energy: 100,
325+
}
220326

221-
### Old school: JavaScript
327+
@Action(actionTypeCatEat)
328+
addEnergy(state: IReducerCatState, action: { payload: number }) {
329+
return {
330+
energy: state.energy + action.payload,
331+
}
332+
}
333+
334+
@Action(actionTypeCatPlay, actionTypeCatBeAwesome)
335+
wasteEnegry(state: IReducerCatState, action: { payload: number }) {
336+
return {
337+
energy: state.energy - action.payload,
338+
}
339+
}
340+
}
341+
342+
const reducer = ReducerCat.create()
343+
```
344+
345+
> You might have noticed that we always pass actions to `Action` in this version. It's because we no longer use classes for our actions and TypeScript can not provide type metadata.
346+
347+
<details>
348+
<summary>JavaScript version</summary>
222349

223350
```js
224351
import { Action, ReducerClass } from 'reducer-class'
@@ -250,6 +377,8 @@ class ReducerCat {
250377
const reducer = ReducerCat.create()
251378
```
252379

380+
</details>
381+
253382
## Integration with `immer`
254383

255384
If your reducer expects 3 arguments `reducer-class` automatically wraps it with `produce` from [immer](https://github.com/mweststrate/immer).
@@ -348,3 +477,4 @@ console.log(res2) // logs 135: 130 - previous value, 5 is added by addEnergy
348477
1. `@Action` can be used to automatically reflect a corresponding action from the type.
349478
1. `ngrx-actions` doesn't allow matching several reducers to the same action, while `reducer-class` allows you to do that and merges them for you.
350479
1. `reducer-class` is built with both worlds, Angular and Redux, in mind. It means equal support for all of them!
480+
1. `reducer-class` works with function-based action creators and supports [redux-actions](https://github.com/redux-utilities/redux-actions) out-of-the-box.

0 commit comments

Comments
 (0)