Reputation: 2212
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.
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
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