Skip to content

Commit

Permalink
Use actions getter to define dispatchers. Closes #9
Browse files Browse the repository at this point in the history
  • Loading branch information
gaguirre committed Mar 12, 2017
1 parent f469f2c commit 8f331ea
Showing 1 changed file with 75 additions and 12 deletions.
87 changes: 75 additions & 12 deletions src/Reduxable.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,33 @@ export default class Reduxable {
this._scope = scope;
}

dispatch() {
this.constructor._store.dispatch(arguments);
/*
* If store exists, then call the store's `dispatch`
* If not, apply the reducer to the local state
*/
dispatch(action) {
const store = this.constructor._store;
if (store) {
return store.dispatch(action);
}

const { type, payload } = action;
this._localState = this.reducers[type](this.getState(), payload);
}

/*
* Returns the state for this particular scope
*
* Given the following structure for a Redux store
*
* const reduxStore = createStore(combineReducers({
* a: combineReducers({
* b: thisReduxableInstance
* })
* })
*
* Then `thisReduxableInstance.getState()` will return `reduxStore.getState().a.b`
*/
getState() {
if (!this.constructor._store) {
return this._localState || this.initialState;
Expand All @@ -24,6 +47,16 @@ export default class Reduxable {
return this._scope.split('.').reduce((object, scopeKey) => object[scopeKey], state);
}

/*
* Returns a reducer function grouping all the defined reducers
*
* This method will do the following
* 1) Check that the action `scope` match with the scope of this Reduxable instance
* 2) Find the method that matchs with the action `type`
* 3) Call that method with the current state and the action `payload`
* 4) Check that the new state retrieved by that method is not the same
* (i.e the method did not mutate the previous state)
*/
getReducer() {
return (state = this.initialState, { type, scope, payload }) => {
if (scope !== this._scope) {
Expand All @@ -44,6 +77,25 @@ export default class Reduxable {
};
}

/*
* Returns an object with all the action creators for the defined reducers
*
* This method will iterate over all the defined `reducers` and create a new
* object of methods (action creators)
*
* ```
* class ReduxableExample extends Reduxable {
* reducers = {
* foo: () => {}
* }
* }
*
* const reduxableInstance = new ReduxableExample()
* const action = reduxableInstance.actions.foo('hello world')
* console.log(action)
* // { type: 'foo', payload: 'hello world', scope: '...' }
* ```
*/
get actions() {
if (!this._actions) {
this._actions = {};
Expand All @@ -58,20 +110,31 @@ export default class Reduxable {
return this._actions;
}

/*
* Returns an object with methods that dispatch an action based on each reducer
*
* ```
* class ReduxableExample extends Reduxable {
* reducers = {
* foo: () => {}
* }
* }
*
* const reduxableInstance = new ReduxableExample()
* reduxableInstance.dispatchers.foo('hello world')
* // Will dispatch an action like => { type: 'foo', payload: 'hello world', scope: '...' }
* ```
*/
get dispatchers() {
if (!this._boundedActions) {
this._boundedActions = {};
const dispatch = this.constructor._store ? this.constructor._store.dispatch : null;
if (!this._dispatchers) {
this._dispatchers = {};

for (const reducerName in this.reducers) {
if (this.reducers.hasOwnProperty(reducerName)) {
this._boundedActions[reducerName] = dispatch
? payload => dispatch({ payload, type: reducerName, scope: this._scope })
: payload => this._localState = this.reducers[reducerName](this.getState(), payload);
}
for (const reducerName in this.actions) {
const actionForReducer = this.actions[reducerName];
this._dispatchers[reducerName] = payload => this.dispatch(actionForReducer(payload));
}
}

return this._boundedActions;
return this._dispatchers;
}
}

0 comments on commit 8f331ea

Please sign in to comment.