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

Accept initialState function to allow dynamic initial state in AoT #51

Closed
bfricka opened this issue Jun 29, 2017 · 13 comments · Fixed by #59
Closed

Accept initialState function to allow dynamic initial state in AoT #51

bfricka opened this issue Jun 29, 2017 · 13 comments · Fixed by #59

Comments

@bfricka
Copy link
Contributor

bfricka commented Jun 29, 2017

This is problem carried over from @ngrx/store (see: 273, 348).

AoT requires static objects in module definitions, so dynamic initial state is only possible with:

  1. At least support for an initialState function
    or
  2. Putting a meta-reducer on top of everything for this purpose alone (as described in my comment on 348). The second case seems unnecessarily unnecessarily complicated for something so easy to support in the library itself.
@robwormald
Copy link
Contributor

Seems legit. Want to take a crack at making a PR?

@brandonroberts
Copy link
Member

You can also provide your own initial state through the INITIAL_STATE token.

import { INITIAL_STATE } from '@ngrx/store';

// in the providers array
{ provide: INITIAL_STATE, useFactory: getInitialState }

@bfricka
Copy link
Contributor Author

bfricka commented Jul 3, 2017

@brandonroberts That's a great idea, and I'm a bit embarrassed I didn't think to do it.

That said, allowing initialStateFactory to take a function is really trivial, and considering it's necessary for AoT, it might be worthwhile to add support for it.

I'm happy to open a PR, but I'm wondering your thoughts. Either a PR documenting how to override the provider (since you're exporting all the tokens), or a PR allowing initialState to be a function.

Thanks

@brandonroberts
Copy link
Member

@bfricka a PR allowing initialState to be a function along with documentation would be good.

bfricka added a commit to bfricka/platform that referenced this issue Jul 4, 2017
bfricka added a commit to bfricka/platform that referenced this issue Jul 4, 2017
@bfricka
Copy link
Contributor Author

bfricka commented Jul 5, 2017

@brandonroberts @robwormald This PR should be ready to. It looks like there's perhaps an issue with the COVERALLS_REPO_TOKEN environment variable not being set in CircleCI. You can add it to the circle project without committing it to git (Project settings > Environment Variables).

bfricka added a commit to bfricka/platform that referenced this issue Jul 5, 2017
@maxisam
Copy link
Contributor

maxisam commented Jul 21, 2017

@bfricka Could you explain how to use initialStateFactory to dynamically get the initial state from the backend?

@bfricka
Copy link
Contributor Author

bfricka commented Jul 23, 2017

This may seem like an odd question, but do you need initial state before the application is loaded? Like, are you trying to re-hydrate state saved on the backend? Because there is an inherent problem with this approach if so: You'd need to delay instantiation of your application until you successfully retrieved the initial state. Otherwise, it's just updating state.

Providing initial state implies that you have access to it, and if you don't you probably shouldn't hold up application bootstrap specifically for that purpose (see "Shell Architecture").

All this said, a standard way of providing initial state is described now in the docs.

Just FYI, the use case I applied this to was retrieving initial state via WebView#addJavaScriptInterface on Android.

@Dunos
Copy link

Dunos commented Sep 5, 2017

@bfricka in the official docs, the way the example get the initial state, the const initialStateFromSomewhere its supposed to be "dynamically injected at runtime". Could you care to detail how that could be achieved? I know probably this is not ngrx business exactly but it probably would help a lot to lost ppl like me :/

@bfricka
Copy link
Contributor Author

bfricka commented Sep 8, 2017

@Dunos Yeah, so intialStateFromSomewhere means a state object (probably partial slice) that is available at runtime and is not statically defined in the code. Somewhere could be from a number of synchronous sources:

  • Provided in the HTML from the server (global)
  • Re-hydrated from Web Storage (e.g. localStorage)
  • Loaded via synchronous XHR (e.g. YAML.load, don't do this)

Ideally, this could be an asynchronous function, but @ngrx is synchronous.

@CharlieGreenman
Copy link

CharlieGreenman commented Jan 30, 2018

Just to re-iterate what @Dunos said. I think an official doc, stating how initialStateFromSomewhere would be achieved would be terrific. I just created the following feature request #770, and part of me says that I might already be able to do this.

@pchristou
Copy link

pchristou commented Feb 6, 2018

Apologies if I'm missing something glaringly obvious but what if I wanted to call a service from within the getInitialState() function? I have an Angular Service that reads a local JSON file and I want to dynamically set a config item stored in the store on load. Is something like that possible?

// Static state
const initialState = { counter: 2 };

// In this function dynamic state slices, if they exist, will overwrite static state at runtime.
export function getInitialState() {

// what if you wanted to call an Angular service from here to populate the "dynamicVar" variable?
  return { ...initialState, ...dynamicVar };
}

@NgModule({
  imports: [
    StoreModule.forRoot(reducers, { initialState: getInitialState })
  ]
})

EDIT - I'm guessing I'd have to do the following (unless I'm missing something) - https://stackoverflow.com/a/41211624

@dereklin
Copy link

dereklin commented Jun 6, 2018

I also want to use a service to get/set some initial state. Is there plan to allow injecting service inside reducers? Or do we just manually initialize a service and use it in the reducer? For now, I am manually dispatching some action with payload to update the state during component initialization.

@SerkanSipahi
Copy link
Contributor

SerkanSipahi commented Jan 2, 2019

@maxisam @VinodhSubramanian1193 @bfricka this is little bit to late but maybe it can help you and others when loading from localstore/indexeddb respectively sync/async into ngrx/store dynamic => https://medium.com/whozapp/use-indexeddb-with-ngrx-for-fast-angular-bootstrap-d9900f0cbc1b

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

Successfully merging a pull request may close this issue.

9 participants