Как вызвать правильную «коллекцию» магазина с помощью ngrx-store?

У меня есть две коллекции данных (пример приложения - попытка изучить ngrx) счетчика и URL-адресов. Я могу правильно вытащить и отобразить каждый из двух магазинов в соответствующих компонентах. Используя пример счетчика из ngrx-store, я также могу увеличивать и уменьшать счетчик. Я добавил редуктор для URL-адресов, который прямо сейчас имеет значение по умолчанию в переключателе действий.

ПРОБЛЕМА: когда я увеличиваю счетчик, также запускается действие по умолчанию для URL. Я неправильно выбираю только 1 действие на 1 редуктор. Как я могу это сделать?

ВОЗМОЖНЫЙ ОТВЕТ?: Я думаю, что действия каждого редуктора должны быть разными? То есть, «встречное приращение» и «приращение URL» по сравнению с обоими редюсерами, использующими «приращение»? Или есть другой метод?

Я новичок в ngrx и rxjs, поэтому будет полезен самый простой/самый прямой код.

// app.module.ts
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import 'rxjs/Rx';
import '@ngrx/core';
import { Store, StoreModule } from '@ngrx/store';

import { AppComponent  }  from './components/app.component';
import { UrlListComponent, UrlItemComponent, ListComponent, ListItemComponent, CounterComponent } from './components/index'
import {  counterReducer, urlReducer} from './reducers/index';

@NgModule({
  imports: [ 
    BrowserModule, 
    FormsModule, 
    HttpModule,
    StoreModule.provideStore({counter: counterReducer, urls: urlReducer}) 
    ],
  declarations: [ AppComponent, UrlItemComponent, UrlListComponent, ListComponent, ListItemComponent, CounterComponent],
  bootstrap: [ AppComponent]
})
export class AppModule { 
  constructor(){console.log("AppModule");}
}

// app.component.ts
import { Injectable, Component, Output, Input, EventEmitter, ChangeDetectionStrategy } from '@angular/core';
import { HttpModule  } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import { Store } from '@ngrx/store';
import { INCREMENT, DECREMENT, RESET, Url } from '../reducers/index';
import { ListComponent, UrlListComponent, CounterComponent} from './index'

export interface AppState {
  counter: number;
  urls : Url[]
}

@Component({
    moduleId: module.id, //system js variable name for relative path
    selector: 'my-app',
    template: `
        <counter-comp [counter]="counter" ></counter-comp>
        <url-list [urls]="urls"></url-list>
        <list [innerArray]="myarray"></list>
    `,
    providers: [],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
    counter: number;
    urls: Url[];
    myarray: number[] = [];

    constructor(private store: Store<AppState>){
        console.log('AppComponent constructor');

        this.store.select(state => state.counter)
            .subscribe(data => this.counter = data);
        this.store.select(state => state.urls)
          .subscribe(data => this.onUrlsEmitted(data));

        this.myarray.push(1);
        this.myarray.push(2);
        this.myarray.push(3);
    }

    ngOnInit() {
            console.log('AppComponent ngOnInit');
    }
    // executed once user data arrives from the store
    public onUrlsEmitted(data:Url[]){
        console.log('AppComponent onUrlsEmitted');
        this.urls = data;
        if(!data || !data.length){ 
            console.log("no url data arrived");
        }
    }
}

// counter.component.ts
import { Component, Input } from '@angular/core';
import { Url, AppState, INCREMENT, DECREMENT, RESET } from '../reducers/index';
import { Store } from '@ngrx/store';

@Component({
  selector: 'counter-comp',
  template: `
        <div class='counter'>
        <div>Current Count: {{ counter }}</div>
        <button (click)="increment()">Increment</button>       
        <button (click)="decrement()">Decrement</button>
        <button (click)="reset()">Reset Counter</button>
        </div>
  `
  ,
    styles:[`
        div { width: 100%; }
        .counter { background-color: #99bbff; }
    `]
})
export class CounterComponent {
  @Input() counter: number;

    constructor(private store: Store<AppState>){
    }

    increment(){
        console.log("counter.component.ts increment");
        this.store.dispatch({ type: INCREMENT });
    }

    decrement(){
        console.log("counter.component.ts decrement");
        this.store.dispatch({ type: DECREMENT });
    }

    reset(){
        console.log("counter.component.ts reset");
        this.store.dispatch({ type: RESET });
    }
    ngOnInit() {
        console.log('CounterComponent input: ' + this.counter);
    }
}

// counter.ts
import { ActionReducer, Action } from '@ngrx/store';

export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const RESET = 'RESET';

export const counterReducer: ActionReducer<number> = (state: number = 0, action: Action) => {
    console.log("counterReducer action.type " + action.type);
     console.log(JSON.stringify(state));
    switch (action.type) {
        case INCREMENT:
            return state + 1;

        case DECREMENT:
            return state - 1;

        case RESET:
            return 0;

        default:
            console.log("counterReducer default");
            return state;
    }
}
// url.ts
import { ActionReducer, Action } from '@ngrx/store';
//export const INCREMENT = 'INCREMENT';
//export const DECREMENT = 'DECREMENT';
//export const RESET = 'RESET';

export interface Url{
    id: number;
    name: string;
}

let initialState = function(){
    return [{id:1, name:"Dina"},{id:2, name:"Wayne"},{id:3,name:"kids"}];
}

export const urlReducer: ActionReducer<Url[]> = (state: Url[] = initialState(), action: Action) => {
     console.log("urlReducer action.type " + action.type);
     console.log(JSON.stringify(state));
     switch (action.type) {
        default:
            console.log("urlReducer default");
            console.log(state);
            return state;
    }
}

person DFBerry    schedule 28.10.2016    source источник
comment
github — это github.com/dfberry/ng2-quickstart/tree/rxjs-store и докер обновлен, чтобы получить ветку ngrx   -  person DFBerry    schedule 29.10.2016
comment
Можете ли вы сократить этот пример до необходимого минимума?   -  person martin    schedule 29.10.2016


Ответы (1)


Вы должны добавить оператор distinctUntilChanged.

this.store.select(state => state.urls).distinctUntilChanged().subscribe(data => this.onUrlsEmitted(data))

person Shlomi Levi    schedule 29.10.2016
comment
Я пробовал отдельныеUntilChanged. Код по-прежнему запускает urlReducer, когда я имею в виду только увеличение счетчика через counterReducer. Возможно, мне не хватает какой-то настройки, чтобы разделить две «таблицы» на события. - person DFBerry; 29.10.2016
comment
Да. Когда вы отправляете действие, оно должно запускать все редукторы. вот почему мы используем select для типа действия. - person Shlomi Levi; 29.10.2016
comment
подробнее: gist.github.com/btroncone/a6e4347326749f938510#actions - person Shlomi Levi; 29.10.2016
comment
Не store.select внутренне вызывает DifferentUntilChanged? Ссылки: netbasal.com/ github.com/btroncone/ngrx- examples/blob/master/counter/src/app/ gist.github.com/btroncone/ а6е4347326749f938510 - person Marcus; 15.11.2017