RasMason
RasMason

Reputation: 2212

ngrx subscribed store does not update on state change Angular5

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)
})

Upvotes: 4

Views: 10649

Answers (1)

RasMason
RasMason

Reputation: 2212

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;
}

Upvotes: 7

Related Questions