Skip to content
This repository has been archived by the owner on Jan 10, 2018. It is now read-only.

WIP: Provide fractal state management #269

Merged
merged 2 commits into from
Mar 2, 2017

Conversation

MikeRyanDev
Copy link
Member

This is a WIP implementation of #211

Key features:

  • Reducers are now always merged by the library, not the developer
  • Child modules can dynamically insert reducers into their parent, enabling fractal state management
  • Library authors can build on top of @ngrx/store and have it seamlessly integrate with applications also using @ngrx/store
  • State is still stored in a single, immutable tree

@MikeRyanDev
Copy link
Member Author

Todo:

  • Expand unit test coverage (currently at 93.12%)
  • Greatly expand documentation
  • Validate against more applications

@btroncone
Copy link
Contributor

I would like to pick up on docs again / start updating older examples as time allows. Maybe we can discuss long term plans for docs soon and begin filling in the gaps at high priority areas.

Really excellent work on this PR!

@robwormald
Copy link
Contributor

this looks good to me - when you're happy with it lets merge and tag a v3.0.0 beta?

@MarkPieszak
Copy link

Is this something that would work with Lazy-loaded Modules as well? 👍 @MikeRyan52 @robwormald
Exciting stuff!

@arkadiuszsz
Copy link

@MikeRyan52 Is there any estimate as of when this feature gets into mainline?

@kondi
Copy link

kondi commented Dec 9, 2016

What is the status of this? Is there a remaining task list? Can we help somehow?
Would be very useful to bring multi module support.

@Alexandredc
Copy link

Hey guys,

Works great on my project. Thanks a lot !

@MikeRyanDev MikeRyanDev force-pushed the feat/fractal-statemanagement branch 2 times, most recently from e08f3ca to 835bdb5 Compare December 27, 2016 18:21
@MikeRyanDev
Copy link
Member Author

Update on this merge request:

  • We are going to target Angular 4.0.0 and TypeScript 2.1 for this release. This means we are BLOCKED by Angular upgrading to TypeScript 2.1. You can follow Upgrade to TypeScript 2.1 angular/angular#13294 for progress updates
  • In the original version of this PR the fractal state mechanism was infinitely fractal and components/services in a module would receive an instance of Store scoped to that module's state. This has been adjusted so that all child modules are inserted at the root and all components/services receive the root Store. This makes simplifies the mental model of the fractal state mechanism.
  • With TypeScript 2.1 we can type a lot more of ngrx/store. The string overload of select and combineReducers are now strongly typed. We will be looking into more ways we can flow types throughout the library before release.

@born2net
Copy link

born2net commented Jan 6, 2017

+1 for asking for docs on the new features and how to migrate, tx!!!!
Regards,

Sean
Angular 2 Kitchen sink: http://ng2.javascriptninja.io

@fxck fxck mentioned this pull request Feb 3, 2017
@nweldev nweldev mentioned this pull request Feb 3, 2017
@MikeRyanDev
Copy link
Member Author

Updated to Angular 4 RC 1 and got the tests to pass.

cc @robwormald

@born2net
Copy link

any plans to make a conversion document and detail instructions on how the implementation differs now?
tx as always....

@MikeRyanDev
Copy link
Member Author

@born2net Yes, definitely. The current plan (as far as I am aware) is to rollout v4 of all ngrx projects at once with updated documentation.

@born2net
Copy link

awesome, as I for one, am really not sure what the changes are and the ramifications for existing projects, TX!

@robwormald
Copy link
Contributor

robwormald commented Feb 27, 2017 via email

@hccampos
Copy link

Could you guys elaborate on the thought behind eliminating scoped stores? Is it just to make it easier for people getting started?

I feel like the lack of an easy way to scope stores can be a huge drawback in larger applications. Essentially it forces feature modules (as they are called in this PR) to know exactly where they live in the global state tree which breaks encapsulation. I'd like to mount a feature module into the main store, and have everything related to that module (reducers, state, actions, selectors) automatically scoped so that the module doesn't need to know about anything outside of it.

Something like this could be used to deal with actions and reducers: https://medium.com/@insideout.develop/how-to-scale-a-redux-application-with-redux-action-recompose-d836ba27776b#.3ff8u3okg

However, selectors still need to know where in the global state tree they should go look for the required state. If the store was scoped, they would only need to know about the slice of the state that concerns that specific feature module.

@MikeRyanDev
Copy link
Member Author

@hccampos Sure! The decision to eliminate scoped instances of Store is that it created a lot of confusion (what instance of Store do I have? Can I apply a selector to this instance?)

Instead, we have opted to let the features determine where they live in the global state tree by providing their name:

StoreModule.forFeature('featureName', { blog: blogReducer })

This will produce a global state tree that looks like this:

{
  featureName: {
    blog: BlogState
  }
}

We plan on suggesting a naming convention to help prevent naming collisions. For instance, you can expect @ngrx/store to install itself like this:

{
  '@ngrx/store': {
    router: RouterStateSnapshot;
  }
}

What's great is that the library can strongly type the shape of the global state tree:

interface RootState {
  ['@ngrx/router-store']: { router: RouterStateSnapshot };
}

@robwormald
Copy link
Contributor

Actually, i mostly agree with @hccampos here. I think the namespaced state thing is a nice optional feature, but i'm not convinced that's the right solution by default.

I've been prototyping from my end using the injectors to define hierarchy, following the mechanism of the router. This enforces the same kind of visibility scoping as the router, and you end up with a more "extends" type functionality:

//root
{
  foos: [1,2,3] 
}
//lazy child A
{
  aChildren: [ 4, 5, 6] 
}

would expose a computed state of

{
  foos: [ 1, 2, 3 ],
  aChildren: [ 4, 5, 6]
}

This means:

  • a truly singleton dispatcher
  • a Store instance per module injector
  • a root "State", that is combineLatest'd with child states:
parentState.zip(childState, (p, c) => Object.assign({}, p, c));

Benefits:

  • children never "pollute" their parent. this feels much less sketchy to me.
  • follows the same semantics as "one-way" data flow.

@MikeRyanDev
Copy link
Member Author

MikeRyanDev commented Feb 28, 2017

@robwormald I would very reluctant of moving away from a single state object. It provides a clean state rehydration story and makes it easy to integrate with the existing Redux devtools.

Additionally, polluting a global state object doesn't seem so bad since we can check for collisions with typings.

@hccampos
Copy link

I agree with the single global state object at the top. That would indeed make serialization and rehydration easier. However, the child stores themselves need to be scoped so that select can provide their slice of the state and so that the reducers can merge into the correct slice too, without having to know about it. So instead of keeping state for each child store, you keep it at the top and you merge the child states into it when reducing actions.

To avoid confusion about which store you have in a certain place, you could have two injectable stores per lazy module, the RootStore and the Store. Or even just a parent and/or isRoot() in the single Store instance.

Imho, it would go right in line with the hierarchical structure of Angular's injectors. I do agree, nevertheless, that it would probably be better if this could be an optional feature so that people don't have to deal with it in simpler apps, examples, etc.

@born2net
Copy link

My two cents is that it's perfect the way it is today and I hope whatever you do moving forward, that it will be backward-compatible. if it ain't broken why fix it and I don't think it's broken right now...

@hccampos
Copy link

Just leaving this for reference here: https://github.com/salsita/prism

The way they scope the redux store so that each component "instance" only sees what concers it is similar to what could be achieved via Angular's hierarchical injectors.

@born2net
Copy link

born2net commented Mar 1, 2017

Isn't this now going back to the flux architecture of multi-store?

@hccampos
Copy link

hccampos commented Mar 1, 2017

@born2net nope, still single store, but with projections of the store for different components/modules. It is how Elm works (Prism used to be called redux-elm) and it is imho, the most elegant solution for large applications.

As it stands, if you move a module around, you have to also go and update the selector used to get its slice. And if you want to have two instances of a component with the same reducer chaos ensues and you need to bring in ids, duplicate actions, selectors and reducers.

@born2net
Copy link

born2net commented Mar 1, 2017

ok thanks for the explanation, but what do you mean "if you move a module around"?
if I rename or move modules around, I can still access the same slice of the store as that did not change, I am sure I misunderstand something. Can you explain further?
Thanks again.
Sean

@Juansasa
Copy link

Juansasa commented Mar 1, 2017

@hccampos I agreed, right now using multiple components with the same reducer is way too much of a hassle.

@robwormald
Copy link
Contributor

I'm gonna go ahead and merge this, so we can move forward with porting ngrx into the new monorepo. I'm still up in the air about it, but i'd rather land this and let people experiment with it.

@robwormald robwormald merged commit 32c0fe0 into ngrx:master Mar 2, 2017
@maxime1992
Copy link

MR title is still WIP and fractal state management is now in master :
image

But don't get me wrong, this is really cool ! 🎉 Is there any doc so can try to set this up on some projects ? :)

@MikeRyanDev MikeRyanDev deleted the feat/fractal-statemanagement branch March 3, 2017 12:27
@jbadeau
Copy link

jbadeau commented Mar 4, 2017

Interesting idea over in the mobx universe https://github.com/mobxjs/mobx-state-tree

@Codermar
Copy link

Codermar commented Mar 7, 2017

@robwormald: Could you explain more about "porting ngrx into the new monorepo"? Also, is there a document or post about the general ngrx roadmap, plans, ideas etc?

@Matmo10
Copy link

Matmo10 commented Mar 9, 2017

Any ETA on some basic docs? Would love to start experimenting with this, but not sure how to yet.

@nitink85
Copy link

@MikeRyan52 Is there any plan to release fractal state management with @angular/core@2.0.0 and typescript@2.0.2?

@vkvarma
Copy link

vkvarma commented Mar 17, 2017

i need some help regarding ngrx/store fractal state management
i saw https://github.com/MikeRyan52/store/tree/feat/better-fractal-statemanagement this branch which is developed by you ... is this fully functional ?
i am getting below error when using with angular 4 rc 1 Unhandled Promise rejection: No provider for Dispatcher! ; Zone: ; Task: Promise.then ; Value: Error: No provider for Dispatcher!

@ngFor
Copy link

ngFor commented Apr 12, 2017

So is it safe to say we just have to wait for the v3 release coming from the new monorepo to use this? What are the plans here? Wouldn't it be good to get community feedback so it can be improved (if necessary) for the next release?

@MikeRyanDev
Copy link
Member Author

MikeRyanDev commented Apr 12, 2017

@ngFor Yes, you have to wait for the monorepo to stabilize. Getting Store working with fractal state was only part of the challenge. Now we are working on router-store, store-devtools, and effects.

Once everything is ready to go we will distribute an alpha version of v4. We'll gather community feedback and shape a final release for (hopefully) May.

brandonroberts added a commit that referenced this pull request Apr 20, 2017
brandonroberts added a commit that referenced this pull request Apr 20, 2017
This reverts commit 32c0fe0.

This keeps this repo at version 2.x so we can keep the docs current and the monorepo will move forward with V4
brandonroberts added a commit that referenced this pull request Apr 20, 2017
brandonroberts added a commit that referenced this pull request Apr 20, 2017
* Revert "WIP: Provide fractal state management (#269)"

This reverts commit 32c0fe0.

* fix(deps): Fixed peer dependencies to support Angular 4.x

Also fixed test setup
@marcguilera
Copy link

Is there any update on this? Should we use ngrx/platform nightly?

@Matmo10
Copy link

Matmo10 commented May 19, 2017

@marcguilera Yes, use ngrx/platform nightly builds. There are docs in the new repo explaining how. If you're using angular-cli, make sure you use one of the newest versions that has typescript 2.3 support.

@jd-carroll
Copy link

The angular-cli now supports typescript 2.3, any update on when this might be released?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet