Skip to content

Commit

Permalink
Add fallback options
Browse files Browse the repository at this point in the history
  • Loading branch information
pauldijou committed Jan 27, 2018
1 parent 1a99aa2 commit ed92c58
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 8 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 1.6.0

- Add `fallback` option to handle any non-supported action inside a reducer.
- Ignore any action which type starts with "@@redux/". This can be a **breaking change** but should not be since you should never handle those actions.

# 1.5.1

- Add missing TS types. (thanks @comerc)
Expand Down
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ const reducerFactory = createReducer(function (on, off) {

Like everything, a reducer is just a function. It takes the current state and an action payload and return the new state. It has the following methods.

**options(object)**
**options({ payload: boolean, fallback: [handler] })**

Since an action is an object with a `type`, a `payload` (which is your actual data) and eventually some `metadata`, all reduce functions directly take the payload as their 2nd argument and the metadata as the 3rd by default rather than the whole action since all other properties are handled by the lib and you shouldn't care about them anyway. If you really need to use the full action, you can change the behavior of a reducer. Returns the reducer itself for chaining.

Expand All @@ -346,6 +346,23 @@ reducer.options({

You can read [a more detailed explanation here](https://github.com/pauldijou/redux-act/issues/49).

If you specify a `fallback` handler, which has the exact same signature as any action handler inside the reducer, it will be called anytime you dispatch an action which is not handled by the reducer.

```javascript
const action = createAction();
const reducer = createReducer({}, 0);
reducer.options({
// action is not handled, so fallback will be called
fallback: (state, payload) => state + payload,
});
const store = createStore(reducer);
store.getState(); // 0
store.dispatch(action(5));
store.getState(); // 5
store.dispatch(action(-10));
store.getState(); // -5
```

**has(action creator)**

Test if the reducer has a reduce function for a particular action creator or a string type.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "redux-act",
"version": "1.5.1",
"version": "1.6.0",
"license": "Apache-2.0",
"description": "An opinionated lib to create actions and reducers for Redux",
"keywords": [
Expand Down
17 changes: 11 additions & 6 deletions src/createReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ function normalizeType(typeOrActionCreator) {

export default function createReducer(handlers = {}, defaultState) {
const opts = {
payload: true
payload: true,
fallback: null,
};

const reducer = Object.assign(reduce, {
Expand Down Expand Up @@ -63,15 +64,19 @@ export default function createReducer(handlers = {}, defaultState) {
}

function reduce(state = defaultState, action) {
if (action && handlers[action.type]) {
if (!action) { return state; }
if (action.type.startsWith('@@redux/')) { return state; }

const handler = handlers[action.type] || opts.fallback;
if (handler) {
if (opts.payload) {
return handlers[action.type](state, action.payload, action.meta);
return handler(state, action.payload, action.meta);
} else {
return handlers[action.type](state, action);
return handler(state, action);
}
} else {
return state;
}

return state;
};

return reducer;
Expand Down
14 changes: 14 additions & 0 deletions test/createReducerTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,4 +369,18 @@ describe('createReducer', function () {
store.dispatch(a1());
expect(store.getState()).to.deep.equal({ one: 3, two: 3, three: 1 });
});

it('should support fallback options', function () {
const action = createAction();
const reducer = createReducer({}, 0);
reducer.options({
fallback: (state, payload) => state + payload,
});
const store = createStore(reducer);
expect(store.getState()).to.equal(0);
store.dispatch(action(5));
expect(store.getState()).to.equal(5);
store.dispatch(action(-10));
expect(store.getState()).to.equal(-5);
});
});

0 comments on commit ed92c58

Please sign in to comment.