store
store copied to clipboard
WIP feat: lazy loaded reducers
This is the beginning thoughts for how to address the ability to be able to load reducers into your state piecemeal if you are using a nested NgModule application structure and also to be able to lazy load parts of your state if you so wish.
I chose the forRoot / forChild paradigm to start considering other work in the Angular ecosystem like @angular/router. This could also be done simply with NgRedux.configureStore and the new NgRedux.addReducers if that's more desirable for the public API.
Still TODO:
- [ ] Verify provider functionality with
angular-redux/example-app - [ ] Determine whether changes need to be made to the mock/testing utilities
- [ ] Add an article describing how to accomplish lazy loading to the docs
@e-schultz @SethDavenport @danielfigueiredo @rpdasilva thoughts and comments appreciated
@smithad15 if I'm understanding this correctly - this doesn't need to be a breaking change - as the old way of configuring a store still works? - matter of putting it in the 6.x branch vs 7.x
Some things I've wondered though when it comes to lazy-loading reducers are:
-
What if an action gets dispatched that you expect to be handled by a reducer that will be lazy loaded, but isn't loaded yet? - if you keep to the pattern of any action creators that are part of this, get lazy loaded at that time - and the reducer doesn't handle actions that are not part of this, it's not an issue.
-
What about use-cases for middleware - although if using something like redux-observable, they already have ways to adding new epics async
For general middleware (loggers, etc) - I see them being app-wide and this isn't an issue, and for things like epics - there are ways of doing this, and I guess just ensuring that things like epics get added before the reducers/actions get dispatched? - this might be a non-issue, and simply a matter of documentation and not something that needs to be baked into the code. Just something to think about
@e-schultz Yes, this is not a breaking change and can be put into 6.x as it is still compatible with the existing way of configuring the store. The only thing it might break is if someone was upgrading from when we still used forRoot (maybe v4? Can't remember). That was removed around the beginning of the new year from my memory so I think there has been a reasonable amount of time to resolve that concern.
I've had thoughts about the same things (actions, middleware, etc.):
-
For actions dispatched before the reducer is loaded, I think this just falls under the usual "foot-guns" of lazy-loading anything. If it's a pattern that you are choosing to implement, then to me it's up to the developer to make sure they are handling the increased complexity that comes with it. This allows you to do it, how or whether you should do it is a bit of a predicate conversation.
-
In regards to middleware, I briefly entertained the thought of including a helper for loading epics with this library (your exploratory work with an epic loading decorator was the ignition point for that), however it didn't quite feel right at this moment as it would add another dependency. This pattern could be extended to handle that feature in the future if desired though. If the middleware allows for lazy-loading, then there is usually enough ability for the developer to handle that how they see fit. I don't foresee any issues with global middleware, but of course I'll test out that theory with the example application.
TLDR; Yes to much documentation 🙂
My main concerns here are:
- overlap with the logic behind
configureSubStorewhich allows a form of lazy-loaded reducers anyway, and - I'm not sure we should tie it directly to NgModule.
If I were to do this I would instead be inclined to add something like NgRedux.addReducer(reducer:Reducer , basePath:? PathSelector) that relevant components could call at any time, independent of how the module stuff works.
We could then generalize the composeReducers logic currently in fractal-reducer-map.ts to make this a special case of the fractal stuff where the basePath is in fact empty.
I feel that this would:
- not change the init API as much
- result in less code
- decouple reducer registration from NgModule completely, resulting in a more granular ability to load reducers.
I'm up for removing the NgModule related parts. I'll look into refactoring the subStore things into the feature as described, but my main concern was that I didn't actually want to scope added reducers like they are with subStores. The idea was to have them globally available. I'll look into this more as I feel like maybe I don't currently have a full grasp of the subStore implementation.
While there is overlap with configureSubStore - what about use cases where once the lazy-loaded thing is mounted - you don't want to limit the actions/etc it receives to be for that slice?
Thinking in terms of a large application - say, each 'tab' is a major feature - lazy load it once you navigate to it, but once there - there is a mix of 'global app state/actions' and 'feature state/actions'.
For example - navigate over to the profile section, change your user name - the app-wide session state needs to get updated.
But, I guess if the basePath is null/undefined - it wouldn't be an issue.
When putting it into a component with configureSubStore, and not in ngModule - what happens then if a person navigates away from that feature, then navigates back? The component gets destroyed/recreated - for the fractalState stuff this makes sense, but when thinking in terms of "sub-apps/large features" - does it make sense?
@SethDavenport Had a chance to update the PR on top of your recent changes and also removing the NgModule bits. I think the configureSubStore logic doesn't quite match up to the use case I'm looking for, but I might be misreading it as well. Next step is still putting together a PR for the example app to showcase the usage pattern.
#453 can you implement ??
Hey, this has slightly fell off my radar - I'm hoping to get some time soon to revisit a few things - but not opposed to getting this in soon, just a matter of time right now.
Any good news regarding this one? I really would like to see this implemented.
@smithad15 hey - since you were doing the initial work on this - I've lost track of where we were. Do you have time to revisit this again and see if we can get a release done with this feature?
I believe @SethDavenport wanted to take a look at refactoring this to include some of the subStore code last we spoke. Documentation and examples still outstanding. Haven’t had much OSS time available as of late, but will try and push the examples and docs portions forward just to confirm that we all like the patterns and use-cases
What's the progress on this please? (I have an enterprise app where features are lazily loaded and each will have it's own set of reducers which need to be added to existing reducers when specific feature lazily loads).
Alternatively, can I somehow use replaceReducers or configureSubstore functionality for this? An example would be extremely useful :)
Is this dead now? I would really like this functionality as well. I have a lazy-loaded module that carries with it a lot of data management code, and currently it all gets included in the main module because I can't seem to figure out how to lazy-load the reducer.
@smithad15 I'm fine with your approach. I'm not going to be refactoring anything any time soon. It's probably not worth the waiting for me since I'm a bit out of the loop on recent Angular changes.