Después de obtener datos con suscripción, quiero enviar acciones como se muestra a continuación. Pero tanto la suscripción como el envío se ejecutan de forma asíncrona, donde no se obliga a apostar ninguna cadena. suscríbete y envía. Tampoco es posible describir el envío dentro de la suscripción, por lo que eso causaría un bucle infinito.
¿Cuál es una mejor manera de enviar acciones cuando obtengo ciertos datos de la suscripción?
Mi código actual es,
// MyApp.ts ngOnInit() { this.store.subscribe(appState => { this.userId = ppState.currentUserId; )}; this.store.dispatch(new LoadInitialData(this.userId); data$ = this.store.select('data'); }Mi posible solución es simplemente implementar en @Effect()...
// MyApp.ts ngOnInit() { this.store.dispatch(new LoadUserId()); } //MyEffectService.ts @Effect() loadUserId$ = this.actions$ .ofType(LOAD_USER_ID) .withLatestFrom(this.store.select('userId') .map([any, userId] => userId) .map(userId => new LoadInitialData(userId));this.store .map(appState => ppState.currentUserId) .do(userId => this.store.dispatch(new LoadInitialData(userId)) .subscribe(userId => this.userId = userId);Use set Immediate, debería enviar el evento al último en el ciclo
this.store.subscribe(appState => setImmediate(() => { this.userId = ppState.currentUserId this.store.dispatch(new LoadInitialData(this.userId) }) ))La solución "posible" que mencionaste se ve bien.
Es una buena práctica mantener su componente inteligente (o contenedor) simple, sin demasiada lógica empresarial.
Es por eso que le sugiero que cambie el nombre de su acción a "Cargar" o "InitView", "Abrir"... para que coincida mejor con la acción real. (aquí inicialización de vista, o apertura de vista...). En el futuro, podría imaginar hacer más cosas (que solo cargar datos de usuario...) cuando se inicialice el componente. Su código dentro del componente se mantendrá simple con solo una acción enviada. La lógica empresarial permanece dentro de su efecto.
Sobre eso, echa un vistazo a esta buena conferencia de Mike Ryan: Good Action Hygiene con NgRx
Entonces, suena perfectamente bien usar un efecto para enviar otra acción (cargar los datos necesarios...).
Ejemplo (sin nueva sintaxis de creador de efectos/acciones):
// MyApp.ts ngOnInit() { this.store.dispatch(new Init()); } // MyEffectService.ts @Effect() init$ = this.actions$ .ofType(Init) .withLatestFrom(this.store.select(selectors.getUserId) .map([any, userId] => userId) .map(userId => new LoadInitialData(userId)); PD: otra buena práctica es usar siempre el selector para recuperar una porción de su estado. (en el ejemplo anterior, utilicé selectors.getUserId )