Skip to content

Commit

Permalink
Ready for 0.3
Browse files Browse the repository at this point in the history
  • Loading branch information
pauldijou committed Dec 20, 2015
1 parent e5dc7e4 commit b74d3df
Show file tree
Hide file tree
Showing 14 changed files with 315 additions and 62 deletions.
31 changes: 27 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This is probably the last release before 1.0. Just want to battle test it in pro

Those functions replace `bindTo` and `bindAll`. Same feature.

## bindTo
## bindTo and bindAll

Now returns a new action creator which will act just like the original one but no longer mutate it.

Expand Down Expand Up @@ -57,20 +57,20 @@ dispatch(batch(a1(), a2(), a3()));
dispatch(batch([a1(), a2(), a3()]));
```

:warning: **Warning** This does not work with binded or assigned action creators. They need to return an action object, not automatically dispatch it. If you are using those features (because, you know, they are awesome), you can call the `???` method to retrieve the action object directly without dispatching it.
:warning: **Warning** This does not work with binded or assigned action creators. They need to return an action object, not automatically dispatch it. If you are using those features (because, you know, they are awesome), you can call the `act` method to retrieve the action object directly without dispatching it.

```javascript
// Assigned action creators
const a1 = createAction();
const a2 = createAction();
a1.assignTo(store);
a2.assignTo(store);
store.dispatch(batch(a1.???(), a2.???()));
store.dispatch(batch(a1.act(), a2.act()));

// Binded action creators
const a1 = createAction().bindTo(store);
const a2 = createAction().bindTo(store);
store.dispatch(batch(a1.???(), a2.???()));
store.dispatch(batch(a1.act(), a2.act()));
```

You can do some other funny stuff, just because.
Expand Down Expand Up @@ -103,6 +103,29 @@ store.disbatch(a1(), a2());
store.disbatch([a1(), a2()]);
```

## Action creator status

You can now test the status of an action creator.

```javascript
const action = createAction();
const store = createStore(() => 0);

action.assigned(); // false, not assigned
action.binded(); // false, not binded
action.dispatched(); // false, test if either assigned or binded

action.assignTo(store);
action.assigned(); // true
action.binded(); // false
action.dispatched(); // true

const bindedAction = action.bindTo(store);
bindedAction.assigned(); // false
bindedAction.binded(); // true
bindedAction.dispatched(); // true
```

# 0.2.0

## Metadata
Expand Down
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ npm install redux-act --save
- [API](#api)
- [createAction](#createactiondescription-payloadreducer-metareducer)
- [createReducer](#createreducerhandlers-defaultstate)
- [assignAll](#assignAllactioncreators-stores)
- [bindAll](#bindAllactioncreators-stores)
- [assignAll](#assignallactioncreators-stores)
- [bindAll](#bindallactioncreators-stores)
- [batch](#batchactions)
- [disbatch](#disbatch)
- [disbatch](#disbatchstore--dispatch-actions)
- [Cookbook](#cookbook)
- [Async actions](#async-actions)
- [Enable or disable batch](#enable-or-disable-batch)
Expand Down Expand Up @@ -179,7 +179,7 @@ serializeTodo(1);
// return { __id__: 'SERIALIZE_TODO', type: 'SERIALIZE_TODO', payload: 1 }
```

Remember that you still need to dispatch those actions. If you already have one or more stores, you can assign the action using the `assignTo` function. This will mutate the action creator itself. If you need immutability, you can use `bindTo`. It will return a new action creator function which will automatically dispatch its action.
Remember that you still need to dispatch those actions. If you already have one or more stores, you can assign the action using the `assignTo` function. This will mutate the action creator itself. If you need immutability, you can use `bindTo`, it will return a new action creator function which will automatically dispatch its action.

```javascript
let action = createAction();
Expand All @@ -192,13 +192,13 @@ const store = createStore(reducer, 1);
const store2 = createStore(reducer, -1);

// Automatically dispatch the action to the store when called
action = action.assignTo(store);
action.assignTo(store);
action(); // store.getState() === 2
action(); // store.getState() === 4
action(); // store.getState() === 8

// You can assign the action to several stores using an array
action = action.assignTo([store, store2]);
action.assignTo([store, store2]);
action();
// store.getState() === 16
// store2.getState() === -2
Expand Down Expand Up @@ -393,13 +393,13 @@ export bindAll(actions, store);

- **actions** (objects | array): wrap an array of actions inside another action and will reduce them all at once when dispatching it. You can also call this function with several actions as arguments.

:warning: **Warning** Does not work with assigned and binded actions by default since those will be dispatched immediately when called. You will need to use the `???` method for such actions. See usage below.
:warning: **Warning** Does not work with assigned and binded actions by default since those will be dispatched immediately when called. You will need to use the `act` method for such actions. See usage below.

### Usage

Useful when you need to run a sequence of actions without impacting your whole application after each one but rather after all of them are done. For example, if you are using `@connect` from `react-redux`, it is called after each action by default. Using `batch`, it will be called only when all actions in the array have been reduced.

`batch` is an action creator like any other created using `createAction`. You can assign or bind it if you want, especially if you only have one store. You can even use inside reducers. It is enabled by default, but you can remove it and put it back.
`batch` is an action creator like any other created using `createAction`. You can assign or bind it if you want, especially if you only have one store. You can even use it inside reducers. It is enabled by default, but you can remove it and put it back.

```javascript
import { createAction, createReducer, batch } from 'redux-act';
Expand All @@ -413,7 +413,7 @@ const reducer = createReducer({
[dec]: state => state - 1,
}, 0);

store = createStore(reducer);
const store = createStore(reducer);
// actions as arguments
store.dispatch(batch(inc(), inc(), dec(), inc()));
// actions as an array
Expand All @@ -425,10 +425,10 @@ inc.assignTo(store);
dec.assignTo(store);

// You still need to dispatch the batch action
// You will need to use the '???' function on the action creators to prevent
// You will need to use the 'act' function on the action creators to prevent
// the auto-dipatch from the binding
store.dispatch(batch(inc.???(), dec.???(), dec.???()));
store.dispatch(batch([inc.???(), dec.???(), dec.???()]));
store.dispatch(batch(inc.act(), dec.act(), dec.act()));
store.dispatch(batch([inc.act(), dec.act(), dec.act()]));
store.getState(); // 2

// Let's de-assign our actions
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"redux",
"flux",
"action",
"reducer"
"reducer",
"batch"
],
"main": "lib/index.js",
"homepage": "https://github.com/pauldijou/redux-act",
Expand Down
2 changes: 0 additions & 2 deletions src/assignAll.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
export default function assignAll(actions, stores) {
if (!actions || !stores) return;

if (Array.isArray(actions)) {
return actions.map(action => action.assignTo(stores));
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/batch.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import createAction from './createAction';

export default createAction('Batch', (...actions) => {
if (actions && actions.length === 1 && Array.isArray(actions[0])) {
if (actions.length === 1 && Array.isArray(actions[0])) {
return actions[0];
}
return (actions || []);
return actions;
});
2 changes: 0 additions & 2 deletions src/bindAll.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
export default function bindAll(actions, stores) {
if (!actions || !stores) return;

if (Array.isArray(actions)) {
return actions.map(action => action.bindTo(stores));
} else {
Expand Down
4 changes: 4 additions & 0 deletions src/createAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ export default function createAction(description, payloadReducer, metaReducer) {

actionCreator.toString = () => action.id;

actionCreator.act = makeAction;

actionCreator.assignTo = (dispatchOrStores)=> {
dispatchFunctions = normalizeAll(dispatchOrStores);
return actionCreator;
Expand All @@ -93,7 +95,9 @@ export default function createAction(description, payloadReducer, metaReducer) {

actionCreator.bindTo = (dispatchOrStores) => {
const bindedActionCreator = makeAndDispatch(normalizeAll(dispatchOrStores));
bindedActionCreator.act = makeAction;
bindedActionCreator.toString = actionCreator.toString;
bindedActionCreator.assignTo = () => bindedActionCreator;
bindedActionCreator.bindTo = () => bindedActionCreator;
bindedActionCreator.assigned = () => false;
bindedActionCreator.binded = () => true;
Expand Down
6 changes: 3 additions & 3 deletions src/disbatch.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import batch from './batch';

export default function disbatch(store, ...actions) {
if (actions) {
if (actions && actions.length > 0) {
if (!store || (typeof store !== 'function' && typeof store.dispatch !== 'function')) {
throw new Error('disbatch must take either a valid Redux store or a dispatch function as first parameter');
throw new TypeError('disbatch must take either a valid Redux store or a dispatch function as first parameter');
}

if (typeof store.dispatch === 'function') {
Expand All @@ -14,7 +14,7 @@ export default function disbatch(store, ...actions) {
return store(batch(...actions));
} else {
if (!store || typeof store.dispatch !== 'function') {
throw new Error('disbatch must take a valid Redux store with a dispatch function as first parameter');
throw new TypeError('disbatch must take a valid Redux store with a dispatch function as first parameter');
}

store.disbatch = disbatch.bind(undefined, store);
Expand Down
9 changes: 9 additions & 0 deletions test/batchTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,13 @@ describe('batch', function () {
expect(store.getState()).to.equal(1);
expect(spy).to.have.been.called.exactly(1);
});

it('should support empty payload', function () {
const { inc, dec, reducer, store, spy } = init();
expect(store.getState()).to.equal(0);
expect(spy).to.have.been.called.exactly(0);
store.dispatch(batch());
expect(store.getState()).to.equal(0);
expect(spy).to.have.been.called.exactly(1);
});
});
68 changes: 68 additions & 0 deletions test/bindAllTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import chai from 'chai';
import {createStore} from 'redux';
import {bindAll, createAction, createReducer} from '../src/index.js';
const expect = chai.expect;

describe('bindAll', function () {
function init() {
const inc = createAction();
const dec = createAction();
const reducer = createReducer({
[inc]: (state)=> state + 1,
[dec]: (state)=> state - 1
}, 0);
const store = createStore(reducer);
const store2 = createStore(reducer);
return { inc, dec, reducer, store, store2 };
}

it('should support hash', function () {
const { inc, dec, reducer, store, store2 } = init();
const { inc: binc, dec: bdec } = bindAll({inc, dec}, store);
binc();
expect(store.getState()).to.equal(1);
binc();
expect(store.getState()).to.equal(2);
bdec();
expect(store.getState()).to.equal(1);
});

it('should support array', function () {
const { inc, dec, reducer, store, store2 } = init();
const [binc, bdec] = bindAll([inc, dec], store);
binc();
expect(store.getState()).to.equal(1);
binc();
expect(store.getState()).to.equal(2);
bdec();
expect(store.getState()).to.equal(1);
});

it('should support hash and multiple stores', function () {
const { inc, dec, reducer, store, store2 } = init();
const { inc: binc, dec: bdec} = bindAll({ inc, dec }, [store, store2]);
binc();
expect(store.getState()).to.equal(1);
expect(store2.getState()).to.equal(1);
binc();
expect(store.getState()).to.equal(2);
expect(store2.getState()).to.equal(2);
bdec();
expect(store.getState()).to.equal(1);
expect(store2.getState()).to.equal(1);
});

it('should support array and multiple stores', function () {
const { inc, dec, reducer, store, store2 } = init();
const [binc, bdec] = bindAll([inc, dec], [store, store2]);
binc();
expect(store.getState()).to.equal(1);
expect(store2.getState()).to.equal(1);
binc();
expect(store.getState()).to.equal(2);
expect(store2.getState()).to.equal(2);
bdec();
expect(store.getState()).to.equal(1);
expect(store2.getState()).to.equal(1);
});
});
55 changes: 53 additions & 2 deletions test/createActionTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ describe('createAction', function () {
expect(action).to.contain.keys(ID, 'type', 'payload', 'meta');
expect(action[ID]).to.be.a('number');
expect(action.type).to.be.a('string');
if (typeof description === 'string') {
expect(action.type).to.contain(description);
}
expect(action.payload).to.deep.equal(payload);
if (typeof meta !== 'undefined') {
expect(action.meta).to.deep.equal(meta);
Expand Down Expand Up @@ -153,7 +156,7 @@ describe('createAction', function () {
expect(store.getState()).to.deep.equal({first: 42, second: '123, 4 - true0a, false - '});
});

it('should bind to a store', function () {
it('should assign to a store', function () {
const store = createStore(reducer, {first: 0, second: ''});
firstAction.assignTo(store);
secondAction.assignTo(store);
Expand All @@ -172,6 +175,25 @@ describe('createAction', function () {
expect(store.getState()).to.deep.equal({first: 42, second: '123, 4 - true0a, false - '});
});

it('should bind to a store', function () {
const store = createStore(reducer, {first: 0, second: ''});
const bfirstAction = firstAction.bindTo(store);
const bsecondAction = secondAction.bindTo(store);

bfirstAction(1);
expect(store.getState()).to.deep.equal({first: 1, second: ''});

bsecondAction(1, '2', [3, '4']);
expect(store.getState()).to.deep.equal({first: 1, second: '123, 4 - '});

bfirstAction(20);
bfirstAction(21);
expect(store.getState()).to.deep.equal({first: 42, second: '123, 4 - '});

bsecondAction(true, 0, ['a', false]);
expect(store.getState()).to.deep.equal({first: 42, second: '123, 4 - true0a, false - '});
});

it('should chain correctly using assignTo', function () {
const actions = {};
const reducer = createReducer(actions, 0);
Expand Down Expand Up @@ -331,5 +353,34 @@ describe('createAction', function () {
expect(action.assigned()).to.be.false;
expect(action.binded()).to.be.false;
expect(action.dispatched()).to.be.false;
})
});

it('should not be assignable nor bindable once binded', function () {
const store = createStore(() => 0);
const action = createAction().bindTo(store);
expect(action).to.equal(action.assignTo(store));
expect(action).to.equal(action.bindTo(store));
});

it('should return raw actions', function () {
const action = createAction();
const reducer = createReducer({
[action]: (state) => state + 1
}, 0);
const store = createStore(reducer);

testActionCreator(action);
testAction(action(1), 1);
testAction(action.act(1), 1);
expect(store.getState()).to.equal(0);

action.assignTo(store);
testAction(action.act(1), 1);
expect(store.getState()).to.equal(0);

const bindedAction = action.bindTo(store);
testAction(bindedAction.act(1), 1);
expect(store.getState()).to.equal(0);

});
});
Loading

0 comments on commit b74d3df

Please sign in to comment.