Search code examples
ngrxngrx-store

Why the state of my app does not change in my angular app using NGRX?


I'm building a 'hello world' app using NGRX, but the state of my app keeps the initial value even when I'm triggering actions that should change it.

This is my app.module:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { counterReducer } from './contador.reducer';
import { environment } from 'src/environments/environment';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    StoreModule.forRoot({ counter: counterReducer }),
    StoreDevtoolsModule.instrument({
      maxAge: 25,
      logOnly: environment.production,
    })
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts:

import { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { decrement, increment } from './contador/contador.actions';


interface AppState {
  counter: number
}
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  public counter!: number;

  constructor(private store: Store<AppState>) {
    this.store.subscribe(state => {
      console.log('state', state)
      this.counter = state.counter;
    })
  }

  ngOnInit() { }

  inc() {
    this.store.dispatch(increment())
  }

  dec() {
    this.store.dispatch(decrement())
  }
}

app.component.html:

<div class="container-fluid text-center">
  <div class="row">
    <div class="col pt-5">
      <h1>Counter</h1>
      <h2>{{counter}}</h2>
    </div>
  </div>
  <button (click)="inc()" class="btn btn-primary pr-5">increment</button>
  <button (click)="dec()" class="btn btn-primary pr-5">decrement</button>
</div>

counter.reducer.ts:

import { decrement, increment } from './contador/contador.actions';
import { Action, createReducer, on } from "@ngrx/store";

export const initialState = 20;

const _counterReducer = createReducer(initialState,
  on(increment => initialState + 1),
  on(decrement => initialState - 1)
)

export function counterReducer(initialState: number | undefined, actions: Action) {
  return _counterReducer(initialState, actions)
}

contador.actions.ts

import { createAction } from "@ngrx/store"

export const increment = createAction('[counter] increment')
export const decrement = createAction('[counter] decrement')

The only thing I'm seeing is that in the reducer, the increment and decrement imports are not being used in the on() methods as they are unused imports.

I always get the initialValue = 0, no matter if I click the increment or decrement buttons.


Solution

  • The on cases in you reducer are not defined correctly.

    The first argument is the action, second argument is a function which takes the existing state, then returns a modified version of it according to the specified action.

    const _counterReducer = createReducer(initialState,
      on(increment, state => state + 1),
      on(decrement, state => state - 1)
    );