J-man
J-man

Reputation: 1833

Why is my @Effect overwriting existing state with ngrx in Angular 6?

I am using ngrx in an Angular 6 app and I can successfully load data from a database and display it on the screen. However, when I navigate to a new page in the app and then navigate back, the state is not preserved and it appears the @Effect is called again and loads the data from the database again. Here is my code:

Effect

export class ProductEffects {
    constructor(private productService: ProductService, private actions$: Actions) { }

    @Effect()
    loadProducts$: Observable<Action> = this.actions$.pipe(
        ofType(productActions.LOAD_ACTION),
        switchMap(action =>
            this.productsService.getProductDetails().pipe(
                map(product => new productActions.LoadSuccess(product)),
                catchError(err => of(new productActions.LoadError(err)))
            )
        )
    );

Reducer

export interface ProductState {
    product: Product;
}

const initialState: ProductState = {
    product: {}
};

export function reducer(state = initialState, action: Action) {
    switch (action.type) {
        case SET_PRODUCT:
            return { ...state, product: (action as SetProductAction).payload };

        case LOAD_SUCCESS:
            return { ...state, product: (action as LoadSuccess).payload, error: '' };

        default: return state;
    }
}

Actions

export const SET_PRODUCT = '[Product] Set Product';
export const LOAD = '[Product] Load';
export const LOAD_SUCCESS = '[Product] Load Success';
export const LOAD_ERROR = '[Product] Load Error';

export class SetProductAction implements Action {
    readonly type = SET_PRODUCT;
    constructor(public payload: Product) { }
}

export class Load implements Action {
    readonly type = LOAD;
}

export class LoadSuccess implements Action {
    readonly type = LOAD_SUCCESS;
    constructor(public payload: Product) { }
}

export type ProductActions = SetProduct | Load | LoadSuccess;

Store

export interface State extends fromRoot.AppState {
    product: fromProduct.ProductState;
}

// selectors
const getProductState = createFeatureSelector<fromProduct.ProductState>('product');

export const getProduct = createSelector(
    getProductState,
    state => state.product
}

Component

products$: Observable<Product>;

constructor(private store: Store<fromProduct.State>) { }

ngOnInit() {
    this.store.dispatch(new Load());
    this.products$ = this.store.pipe(select(fromProduct.getProduct));
}

Upvotes: 0

Views: 721

Answers (1)

Ren&#233; Winkler
Ren&#233; Winkler

Reputation: 7058

Your ngrx implementation seems all ok to me. What you describe is an absolutely normal behavior. As soon as you navigate away from a page, the component destroyed and the new one is created, i.e. the ngOnInit is called. If you put the Loading logic in the ngOnInit, the state is loaded everytime you navigate to this page.

Upvotes: 1

Related Questions