Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ngrx subscribed store does not update on state change Angular5

Tags:

angular

ngrx

I'm build an app that takes the name of a city sends to an api end point and returns the weather for that city.

It uses an two Actions, one that will update the cities, using the name as the payload, Action two loads the new array returned to update the state

The effect uses switchMap to map the api call then return results.

The select function, to display results of the store, only detects the store updates on initiation of page load (Empty array) and for the first set of results

And does not detect the changes within my store after

the page displays the first object in the array, but there are 3 objects in the state.

enter image description here

app.state:

import { Cities } from '../../model/weather';

//Holds data for city weather
export interface AppState {
  readonly cityWeather: Cities[];
}

In app.module:

import {cityWeather} from './weather/store/reducers/weather';

    export const reducers = {
        cityWeather
     };

 StoreModule.forRoot(reducers, {initialState: undefined})

The reducers:

export function cityWeather(state:Cities[] = [], action:Action) : any {
    switch (action.type)  {
        case LOAD_CITIES_ACTION:
        return  handleLoadCitiesAction(state, action);
        case UPDATE_CITIES_ACTION:
        console.log(state)
        return handleUpdateCitiesAction(state, action);
    default:
        return state;
    }

}
function  handleUpdateCitiesAction(state, action):Cities[]{
    //Must always return the state
    console.log(state, action.payload)
        return state;
}

function  handleLoadCitiesAction(state, action):Cities[]{
    //Return the payload that holds the new array for cities
    console.log(action.payload)
    return action.payload;
}

@Effects

import { Injectable } from '@angular/core';
import {Actions, Effect} from "@ngrx/effects";
import 'rxjs/add/operator/switchMap';
import { WeatherService } from '../../weather.service';
import { UpdateCitiesAction, UPDATE_CITIES_ACTION, LoadCitiesAction } from '../actions/weather';
import {Observable} from "rxjs/Observable";
import {Action} from "@ngrx/store";

@Injectable()
export class WeatherEffects {

  constructor(private actions$: Actions, private weatherService: WeatherService) {

  }

  @Effect() cityWeather$: Observable<Action> = this.actions$
      .ofType<UpdateCitiesAction>(UPDATE_CITIES_ACTION)
      .switchMap(action => {
          console.log(action)
          return this.weatherService.searchWeatherForCity(action.payload)
        })
    .map(cities =>  {
        console.log(cities);
        return new LoadCitiesAction(cities)
    });
}

this is how I subscribe to my store, for testing purposes I'm doing both ways:

@Component({
  selector: 'app-weather',
  template: `
  <app-search (onSearchCity)="citySearch($event)"></app-search>
  <app-results [cities]="cities$ | async "></app-results>  `
})

this.cities$ = this.store.select(state => state.cityWeather);

this.store.select(state => state.cityWeather)
.subscribe((data)=>{
  console.log(data)
})
like image 515
Rasta Avatar asked Oct 20 '25 20:10

Rasta


1 Answers

Solved as soon as I posted, it seems I have to make a copy:

function  handleLoadCitiesAction(state, action):Cities[]{
    let newState = action.payload.slice(); 
    return newState;
}
like image 112
Rasta Avatar answered Oct 22 '25 10:10

Rasta



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!