Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(lib): provide store functionality #185

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 46 additions & 29 deletions src/components/ngRedux.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Connector from './connector';
import invariant from 'invariant';
import {createStore, applyMiddleware, compose, combineReducers} from 'redux';
import digestMiddleware from './digestMiddleware';
import wrapStore from './storeWrapper';

import curry from 'lodash.curry';
import isFunction from 'lodash.isfunction';
Expand All @@ -20,6 +21,11 @@ export default function ngReduxProvider() {
let _storeEnhancers = undefined;
let _initialState = undefined;
let _reducerIsObject = undefined;
let _providedStore = undefined;

this.provideStore = (store) => {
_providedStore = store;
}

this.createStoreWith = (reducer, middlewares, storeEnhancers, initialState) => {
invariant(
Expand All @@ -42,45 +48,56 @@ export default function ngReduxProvider() {
};

this.$get = ($injector) => {
const resolveMiddleware = middleware => isString(middleware)
? $injector.get(middleware)
: middleware;
if (_providedStore) {
const emptyStore = createNgReduxStore($injector, [], [], state => state, undefined);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pass through reducer is throwing errors for me. It's expecting it to be a well formed action object {type: 'foobar'}.

Changed to (state, action) => action.payload and then changed line 6 of the store wrapper to just dispatch as:

ngReduxStore.dispatch({type:'@@NGREDUX_PASSTHROUGH', payload: newState});

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! nice! I figured that might cause some issues.


const resolvedMiddleware = map(_middlewares, resolveMiddleware);
return wrapStore(_providedStore, emptyStore);
}

const resolveStoreEnhancer = storeEnhancer => isString(storeEnhancer)
? $injector.get(storeEnhancer)
: storeEnhancer;
return createNgReduxStore($injector, _middlewares, _storeEnhancers, _reducer, _initialState);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the diff looks a bit weird but I basically moved the this.$get logic out into its own function so that we can create stores on-demand.


const resolvedStoreEnhancer = map(_storeEnhancers, resolveStoreEnhancer);
};

if(_reducerIsObject) {
const getReducerKey = key => isString(_reducer[key])
? $injector.get(_reducer[key])
: _reducer[key];
this.$get.$inject = ['$injector'];
}

const resolveReducerKey = (result, key) => assign({}, result,
{ [key]: getReducerKey(key) }
);
function createNgReduxStore($injector, _middlewares, _storeEnhancers, _reducer, _initialState) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By moving this function out, i'm getting _reducerIsObject is not defined, on line 77. Looks like it doesn't have the scope of all the vars defined at the top of ngReduxProvider()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I resolved it for myself by moving createNgReduxStore inside of the ngReduxProvider method's scope but i'm not sure if that was a good solution or not.

const resolveMiddleware = middleware => isString(middleware)
? $injector.get(middleware)
: middleware;

const reducersObj = Object
.keys(_reducer)
.reduce(resolveReducerKey, {});
const resolvedMiddleware = map(_middlewares, resolveMiddleware);

_reducer = combineReducers(reducersObj);
}
const resolveStoreEnhancer = storeEnhancer => isString(storeEnhancer)
? $injector.get(storeEnhancer)
: storeEnhancer;

const finalCreateStore = resolvedStoreEnhancer ? compose(...resolvedStoreEnhancer)(createStore) : createStore;
const resolvedStoreEnhancer = map(_storeEnhancers, resolveStoreEnhancer);

//digestMiddleware needs to be the last one.
resolvedMiddleware.push(digestMiddleware($injector.get('$rootScope')));
if(_reducerIsObject) {
const getReducerKey = key => isString(_reducer[key])
? $injector.get(_reducer[key])
: _reducer[key];

const store = _initialState
? applyMiddleware(...resolvedMiddleware)(finalCreateStore)(_reducer, _initialState)
: applyMiddleware(...resolvedMiddleware)(finalCreateStore)(_reducer);
const resolveReducerKey = (result, key) => assign({}, result,
{ [key]: getReducerKey(key) }
);

return assign({}, store, { connect: Connector(store) });
};
const reducersObj = Object
.keys(_reducer)
.reduce(resolveReducerKey, {});

this.$get.$inject = ['$injector'];
_reducer = combineReducers(reducersObj);
}

const finalCreateStore = resolvedStoreEnhancer ? compose(...resolvedStoreEnhancer)(createStore) : createStore;

//digestMiddleware needs to be the last one.
resolvedMiddleware.push(digestMiddleware($injector.get('$rootScope')));

const store = _initialState
? applyMiddleware(...resolvedMiddleware)(finalCreateStore)(_reducer, _initialState)
: applyMiddleware(...resolvedMiddleware)(finalCreateStore)(_reducer);

return assign({}, store, { connect: Connector(store) });
}
16 changes: 16 additions & 0 deletions src/components/storeWrapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export default function wrapStore(providedStore, ngReduxStore) {
const unsubscribe = providedStore
.subscribe(() => {
let newState = providedStore.getState();

ngReduxStore.dispatch(newState);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here's where the magic happens. The only thing I'm unsure about is cleanup. But as I understand it, Angular 1 never really "unloads" during runtime so this shouldn't be an issue.

})
;

return Object.assign({},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the intention to not provide .connect() functionality when using a provided store? I fiddled with it and added it back in, the only caveat is that connected actions dispatch to the wrong store, so you always need to use the $ngRedux.dispatch.

providedStore,
{
subscribe: ngReduxStore.subscribe
})
;
}