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

Dynamic Load Reducers #121

Closed
wants to merge 2 commits into from
Closed

Dynamic Load Reducers #121

wants to merge 2 commits into from

Conversation

Negan1911
Copy link

@Negan1911 Negan1911 commented Jan 11, 2017

Hi, i'm from a team of developers that hardly uses angular components, and we don't have a way to share our reducers in the same component level (we have to do a big combine of all reducers), so, taking advantage that the dependency tree runs the .config of every component and in the last time, the root .config, i developed this feature to being able to save your reducers dynamically.

This will help #75 and #80

@m3fawner
Copy link

m3fawner commented Apr 3, 2017

I would really like to see this merged in. In a world of modularity and bundle chunking, this is a feature that becomes more and more of a necessity.

We're attempting to create a store, using its current state as the initial state, while using the newly combined reducers, but it appears that this approach won't work

@Negan1911
Copy link
Author

Until this got merged you could use this https://github.com/Negan1911/ng-redux-injector is just a simple factory that will hold the reducers instances to combine them later :) i hope that this got merged soon

@m3fawner
Copy link

m3fawner commented Apr 3, 2017

Unfortunately, that doesn't solve my issue. Since I still am required to create a new store as a result of the merged in reducer, I have a race case scenario where the object reference change to the store causes the newly fired reducer to drop state.

@m3fawner
Copy link

m3fawner commented Apr 3, 2017

Found a solution that doesn't require a modification to ngRedux.

Ultimately, the createStoreWith takes in a pure function...so the solution? Write a pure function that is dynamic. Here's how I did it:

export default class DynamicReducerLoader {
    createStoreWith(reducers, middlewares, enhancers) {
        if(!this.$ngReduxProvider) {
            throw new Error('DynamicReducerLoader needs to have an $ngReduxProvider assigned to it prior to creating store, please add the provider prior to creating store');
        } else {
            this.currentReducerObject = reducers;
            this.currentReducerFunction = combineReducers(reducers);
            this.$ngReduxProvider.createStoreWith(this.currentReducer.bind(this), middlewares, enhancers);
        }
    }
    currentReducer(state, action) {
        return this.currentReducerFunction(state, action);
    }
    injectReducer(reducer) {
        this.currentReducerObject = Object.assign(this.currentReducerObject, reducer);
        this.currentReducerFunction = combineReducers(this.currentReducerObject);
    }
}

It takes in an object defining the initial reducers (which I then call combine on). The pure function that is passed into the createStoreWith call is that of "currentReducer". This has its internal function replaced dynamically by "injectReducer". So, as reducers are injected, and recombined into a new reducer function, the currentReducer reference does not change, but the behavior of it does.

@Negan1911
Copy link
Author

Awesome!

@m3fawner
Copy link

m3fawner commented Apr 3, 2017

It's not pretty, but it works. I'd prefer that it be built into the provider, as to encapsulate the fact that I require $ngReduxProvider assigned onto the class before it can actually be used. It's yet another layer of abstraction on a layer of abstraction.

@AntJanus
Copy link
Collaborator

AntJanus commented Jul 25, 2017

Hey all,

I actually really like this feature but wouldn't it make more sense to just add a framework-agnostic enhancer?

I created an enhancer called Paradux that does exactly that with vanilla Redux:

function paraduxEnhancer(createStore) {
  return (reducer, initialState, enhancer) => {
   let reducers = [];

   function addReducer(reducerFunc) {
     reducers.push(reducerFunc);
     var unsubscribed = false;

     return function() {
       if (!unsubscribed) {
         reducers.splice(reducers.indexOf(reducerFunc), 1);
         unsubscribed = true;

         return true;
       }

       return false;
     }
   }

   function enhancedReducer(reducer) {
      return (state, action) => {
        var newState = reducers.reduce((tempState, reducerFunc) => {
          return reducerFunc(tempState, action);
        }, reducer(state, action));

        return newState;
      };
   }

   const store = createStore(enhancedReducer(reducer), initialState, enhancer);

   return Object.assign({}, store, { addReducer });
  }
}

I can make it available as an open-source lib and it should solve all the issues without messing with ng-redux directly.

@AntJanus AntJanus mentioned this pull request Sep 14, 2017
@AntJanus
Copy link
Collaborator

I'm going to close this out as it is out of scope for ng-redux.

@AntJanus AntJanus closed this Sep 14, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants