@amcdnl I have MenuState store that needs to fetch JSON data from backend and process and set its default / initial state. I am thinking using of MenuState's constructor to fetch data and set its default state.
is there a way to access StateContext in MenuState constructor? I am thinking to use it to set defaults using setState from StateContext
If not possible via constructor, can we have user provided store's @ initializer method that get called after constructor which will sets default state?
proposed DI for constructor example:
@State<MenuStateModel>({
name: 'menu',
defaults: {
tree: null,
currentlyOpened: [],
}
})
export class MenuState {
constructor({ setState }: StateContext<MenuStateModel>, private store: Store, private menuService: MenuService) {
const _tree = menuService.getDefaultMenu();
setState({
tree: _tree,
currentlyOpened: []
})
}
@Action(ToggleCurrentlyOpened)
toggleCurrentlyOpened({ getState, patchState }: StateContext<MenuStateModel>, { payload }: ToggleCurrentlyOpened) {
patchState({
currentlyOpened: payload
});
}
}
Hey @xmlking, what about dispatching custom InitMenuState action in constructor?
@State<MenuStateModel>({
name: 'menu',
defaults: {
tree: null,
currentlyOpened: [],
}
})
export class MenuState {
constructor(private store: Store, private menuService: MenuService) {
const _tree = menuService.getDefaultMenu();
// Does .getDefaultMenu() return Promise/Observable?
// If yes then .store.dispatch should be called in .then() or .subscribe()
this.store.dispatch(new InitMenuState({
tree: _tree,
currentlyOpened: []
}));
}
@Action(InitMenuState)
initMenuState({ getState, setState }: StateContext<MenuStateModel>, { payload }: InitMenuState) {
setState(payload);
}
@Action(ToggleCurrentlyOpened)
toggleCurrentlyOpened({ getState, patchState }: StateContext<MenuStateModel>, { payload }: ToggleCurrentlyOpened) {
patchState({
currentlyOpened: payload
});
}
}
menuService.getDefaultMenu() return Scalar / Tree data structure.
I am currently using your approach with setTimeout.
export class MenuState {
constructor(private store: Store, private menuService: MenuService) {
const _tree = menuService.getDefaultMenu();
setTimeout(() => {
this.store.dispatch(new InitializeData(_tree));
});
}
@Action(InitializeData)
initializeData({ setState }: StateContext<MenuStateModel>, { payload }: InitializeData) {
setState({
tree: payload,
currentlyOpened: [],
iconMode: false
});
}
what do you think of this proposal?
new decorator @Initializer that get called after constructor , automatically.
export class MenuState {
constructor(private store: Store, private menuService: MenuService) {
}
@Initializer
initializeData({ setState }: StateContext<MenuStateModel>) {
const _tree = this.menuService.getDefaultMenu();
setState({
tree: _tree,
currentlyOpened: [],
iconMode: false
});
}
I like the idea of not doing any work in the constructor, for testing purposes it's better to not cause any side-effects when initializing a new class.
Allthough I'm not sure of the decorator. I think it's better to stick with lifecycle hooks, similar to angular's component lifecycle hooks.
lang=ts
export class MenuState implements NgxsOnInit {
ngxOnInit({ setState}: StateContext<MenuStateModel>) {
....
}
}
Haven't got a chance to look at the code, but I think this should be relatively easy to implement.
With @dietergoetelen's suggestion, this could possible replace the defaults property from the StateOptions
Life cycle hooks are in 3.0
Is there a way to initialize using the lifecycle hook, and have that be the default value for the state? Even after using the hook, the initial value on subscription is still the static value provided in the state class decorator.
^ bump
Most helpful comment
I like the idea of not doing any work in the constructor, for testing purposes it's better to not cause any side-effects when initializing a new class.
Allthough I'm not sure of the decorator. I think it's better to stick with lifecycle hooks, similar to angular's component lifecycle hooks.
lang=ts export class MenuState implements NgxsOnInit { ngxOnInit({ setState}: StateContext<MenuStateModel>) { .... } }Haven't got a chance to look at the code, but I think this should be relatively easy to implement.