Skip to content

Commit e659159

Browse files
committed
Update to Flux Standard Action v0.6.0
- Uses FSA's isError() to check for failed actions - `success()` and `error()` have been renamed to `next()` and `throw()`, which are inspired by the ES6 generator interface.
1 parent 2d52ea7 commit e659159

File tree

5 files changed

+25
-62
lines changed

5 files changed

+25
-62
lines changed

.eslintrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"rules": {
1111
"padded-blocks": 0,
1212
"no-use-before-define": [2, "nofunc"],
13-
"no-unused-expressions": 0
13+
"no-unused-expressions": 0,
14+
"no-reserved-keys": 0
1415
}
1516
}

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ createAction('ADD_TODO')('Use Redux');
3939

4040
Wraps a reducer so that only handles Flux Standard Actions of a certain type.
4141

42-
If a single reducer is passed, it is used to handle both successful and failed actions. You can use this form if you know a certain action will always be a success, like the increment example above.
42+
If a single reducer is passed, it is used to handle both normal actions and failed actions. (A failed action is analogous to a rejected promise.) You can use this form if you know a certain type of action will never fail, like the increment example above.
4343

44-
Otherwise, you can specify reducers for `success` and `error`:
44+
Otherwise, you can specify separate reducers for `next()` and `throw()`. This API is inspired by the ES6 generator interface.
4545

4646
```js
4747
handleAction('FETCH_DATA', {
48-
success(state, action) {...}
49-
error(state, action) {...}
48+
next(state, action) {...}
49+
throw(state, action) {...}
5050
});
5151
```
5252

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"mocha": "^2.2.5"
3535
},
3636
"dependencies": {
37+
"flux-standard-action": "^0.6.0",
3738
"reduce-reducers": "^0.1.0"
3839
}
3940
}

src/__tests__/handleAction-test.js

Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { handleAction} from '../';
1+
import { handleAction } from '../';
22

33
describe('handleAction()', () => {
44
const type = 'TYPE';
@@ -11,12 +11,6 @@ describe('handleAction()', () => {
1111
expect(reducer(prevState, { type })).to.equal(prevState);
1212
});
1313

14-
it('returns previous state if status defined but not one of "error" or "success"', () => {
15-
const reducer = handleAction(type, () => null);
16-
expect(reducer(prevState, { type, status: 'pending' }))
17-
.to.equal(prevState);
18-
});
19-
2014
it('accepts single function as handler', () => {
2115
const reducer = handleAction(type, (state, action) => ({
2216
counter: state.counter + action.payload
@@ -32,13 +26,13 @@ describe('handleAction()', () => {
3226
describe('map of handlers form', () => {
3327
describe('resulting reducer', () => {
3428
it('returns previous state if type does not match', () => {
35-
const reducer = handleAction('NOTTYPE', { success: () => null });
29+
const reducer = handleAction('NOTTYPE', { next: () => null });
3630
expect(reducer(prevState, { type })).to.equal(prevState);
3731
});
3832

39-
it('uses `success()` if status is undefined', () => {
33+
it('uses `next()` if action does not represent an error', () => {
4034
const reducer = handleAction(type, {
41-
success: (state, action) => ({
35+
next: (state, action) => ({
4236
counter: state.counter + action.payload
4337
})
4438
});
@@ -48,43 +42,24 @@ describe('handleAction()', () => {
4842
});
4943
});
5044

51-
it('uses `success()` if status is "success"', () => {
52-
const reducer = handleAction(type, {
53-
success: (state, action) => ({
54-
counter: state.counter + action.payload
55-
})
56-
});
57-
expect(reducer(prevState, { type, payload: 7, status: 'success' }))
58-
.to.deep.equal({
59-
counter: 10
60-
});
61-
});
62-
63-
it('uses `error()` if status is "error"', () => {
45+
it('uses `throw()` if action represents an error', () => {
6446
const reducer = handleAction(type, {
65-
error: (state, action) => ({
47+
throw: (state, action) => ({
6648
counter: state.counter + action.payload
6749
})
6850
});
69-
expect(reducer(prevState, { type, payload: 7, status: 'error' }))
51+
expect(reducer(prevState, { type, payload: 7, error: true }))
7052
.to.deep.equal({
7153
counter: 10
7254
});
7355
});
7456

75-
it('returns previous state if status defined but not one of "error" or "success"', () => {
76-
const reducer = handleAction(type, { success: () => null });
77-
expect(reducer(prevState, { type, status: 'pending' }))
57+
it('returns previous state if matching handler is not function', () => {
58+
const reducer = handleAction(type, { next: null, error: 123 });
59+
expect(reducer(prevState, { type, payload: 123 })).to.equal(prevState);
60+
expect(reducer(prevState, { type, payload: 123, error: true }))
7861
.to.equal(prevState);
7962
});
80-
81-
it('throws if matching handler is not function', () => {
82-
const reducer = handleAction(type, { success: null, error: 123 });
83-
expect(() => reducer(prevState, { type, status: 'success' }))
84-
.to.throw(/is not a function/);
85-
expect(() => reducer(prevState, { type, status: 'error' }))
86-
.to.throw(/is not a function/);
87-
});
8863
});
8964
});
9065
});

src/handleAction.js

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,24 @@
1-
// Map of action statuses to reducer property names
2-
const statusMappings = {
3-
'error': 'error',
4-
'success': 'success'
5-
};
1+
import { isError } from 'flux-standard-action';
62

73
function isFunction(val) {
84
return typeof val === 'function';
95
}
106

11-
// Default action status, if none is specified
12-
const defaultStatus = 'success';
13-
147
export default function handleAction(type, reducers) {
158
return (state, action) => {
169
// If action type does not match, return previous state
1710
if (action.type !== type) return state;
1811

19-
// If status is undefined, use default status
20-
const status = typeof action.status !== 'undefined'
21-
? action.status
22-
: defaultStatus;
23-
24-
// Get reducer key that corresponds to status
25-
const handlerKey = statusMappings[status];
26-
27-
// If status does not correspond to a reducer key, return previous state
28-
if (!handlerKey) return state;
12+
const handlerKey = isError(action) ? 'throw' : 'next';
2913

3014
// If function is passed instead of map, use as reducer
3115
if (isFunction(reducers)) return reducers(state, action);
3216

33-
// Call reducer
34-
// Throws if reducer is not a function
17+
// Otherwise, assume an action map was passed
3518
const reducer = reducers[handlerKey];
36-
return reducer(state, action);
19+
20+
return isFunction(reducer)
21+
? reducer(state, action)
22+
: state;
3723
};
3824
}

0 commit comments

Comments
 (0)