angular - NgRx: Obtener datos del store pero están indefinidos
Querida comunidad de Stackoverflow.
Soy nuevo en NgRx y estoy tratando de descubrir cómo funciona. He creado una aplicación - Lista de Compras simple basada en Angular 6, Firebase y NgRx.
Agregué un par de elementos en una colección llamada Product y estoy intentando obtenerlos mediante patrones de ngrx. Parece que hice todo bien: he obtenido los elementos como payload en GET_PRODUCTS_SUCCESS, pero no puedo ponerlos en la vista para mostrarlos, los productos están indefinidos. Intenté hacerlo de dos maneras:
this.store.select(getProducts).subscribe(products => {
console.log('products', products); // undefined
});
y
this.products = this.store.select(getProducts); // Store
De segunda manera, solo obtengo toda una tienda... Código abajo.
producto.acciones.ts
import { Action } from '@ngrx/store';
import { Product } from '../../models/product.model';
export const GET_PRODUCTS = 'Get_products';
export const GET_PRODUCTS_SUCCESS = 'Get_products_success';
export class GetProducts implements Action {
readonly type = GET_PRODUCTS;
constructor(public payload = '') {}
}
export class GetProductsSuccess implements Action {
readonly type = GET_PRODUCTS_SUCCESS;
constructor(public payload?: Product[]) {}
}
export type Actions = GetProducts | GetProductsSuccess;
producto.reductor.ts
import { Product } from '../../models/product.model';
import * as productAction from './products.action';
export interface State {
products: Product[];
loading: boolean;
}
export const initialState: State = {
products: [],
loading: false,
};
export function ProductsReducer(state: State = initialState, action: productAction.Actions) {
switch (action.type) {
case productAction.GET_PRODUCTS:
return {...state, loading: true};
case productAction.GET_PRODUCTS_SUCCESS:
const test = {...state, products: action.payload, loading: false};
console.log("test", test);
return test;
default:
return state;
}
}
producto.efectos.ts
import { Injectable } from '@angular/core';
import { Action } from '@ngrx/store';
import { Effect, Actions } from '@ngrx/effects';
import { AngularFirestore } from '@angular/fire/firestore';
import { Product } from '../../models/product.model';
import * as productAction from './products.action';
import { Observable, of } from 'rxjs';
import { switchMap, map, mergeMap } from 'rxjs/operators';
@Injectable()
export class ProductEffects {
constructor(private actions$: Actions, private db: AngularFirestore) {}
@Effect()
getProducts: Observable<Action> = this.actions$
.ofType(productAction.GET_PRODUCTS).pipe(
switchMap(() => {
return this.db.collection<Product>('products').valueChanges()
.pipe(
map((payload) => {
return {
type: 'Get_products_success',
payload: payload
};
})
);
})
);
}
producto.selector.ts
import { createSelector } from '@ngrx/store';
import { State } from './products.reducer';
import { Product } from '../../models/product.model';
export function getState(state: State): State {
return state;
}
export function fetchProducts(state: State): Product[] {
return state.products;
}
export const getProducts = createSelector(getState, fetchProducts);
list.component.ts - obtener y mostrar todos los productos
import { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { Product } from '../../models/product.model';
import * as productActions from '../../store/products/products.action';
import { State } from '../../store/products/products.reducer';
import { getProducts } from '../../store/products/products.selector';
import { Observable } from 'rxjs';
@Component({
selector: 'app-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.scss']
})
export class ListComponent implements OnInit {
products: Observable<Product[]>;
constructor(private store: Store<State>) {}
ngOnInit() {
this.store.dispatch(new productActions.GetProducts);
this.store.select(getProducts).subscribe(products => {
console.log('products', products);
});
}
}
Si notas que estoy haciendo algo mal, no dudes en decírmelo. Realmente necesito tu ayuda. Gracias.
Respuesta #1
Descubrí
Busqué cómo más podría hacer una solicitud de mis datos desde la tienda. Encontré una manera, en el contexto de mi aplicación se ve así:
this.store.select(state => state).subscribe(data => {
console.log('data', data);
});
Y obtengo en la consola el objeto:
{ message: { Products: Array[3], loading: false } }
¿Qué significa este mensaje? Hice una búsqueda global y vi que implementé mi reductor en app.module.ts como:
StoreModule.forRoot({ message: ProductReducer }),
Así que creé un index.ts en la carpeta reducers y exporté un reducer a continuación:
import { ActionReducerMap } from '@ngrx/store';
import * as fromProducts from './products.reducer';
export interface AppState {
products: fromProducts.ProductState;
}
export const reducers: ActionReducerMap<AppState> = {
products: fromProducts.productsReducer
};
Y ahora en app.module.ts se importa como:
StoreModule.forRoot(reducers),
y ahora este código está funcionando bien:
this.store.select(getProducts).subscribe(products => {
console.log('products', products);
});
