NgRX выберите состояние хранилища undefined - PullRequest
0 голосов
/ 03 августа 2020

Я новичок в магазине NgRX. У меня возникла проблема с получением данных билетов в компонент билетов с помощью хранилища NgRx.

Я использовал модуль эффектов для получения асинхронных c билетов через метод http get в ticketService

Я не уверен, как настроить свой магазин и селектор для получения информации о билетах. Предоставление URL-адреса stackblitz для воспроизведения проблемы. Заранее спасибо.

https://stackblitz.com/edit/ngrx-demo-ticket

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule} from '@angular/common/http';

import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
import { TicketsComponent } from './tickets/tickets.component';
import { TicketsService } from './tickets.service';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from './environment/environment';
import {TicketReducer} from './store/ticket.reducers';
import {TicketEffects} from './store/ticket.effects';

@NgModule({
  imports:      [ BrowserModule, FormsModule,   HttpClientModule, 
  StoreModule.forRoot(TicketReducer, {}),
  EffectsModule.forRoot([TicketEffects]),
  !environment.production ? StoreDevtoolsModule.instrument() : [],
  ],
  declarations: [ AppComponent, HelloComponent, TicketsComponent ],
  bootstrap:    [ AppComponent ],
  providers: [TicketsService]
})
export class AppModule { }

Tickets.component.ts

import { Component, OnInit } from '@angular/core';
import { TicketsService } from '../tickets.service';

import { of, Observable, pipe } from 'rxjs';
import { Ticket } from '../models/ticket';
import { map, catchError, tap } from 'rxjs/operators';
import { Store, select } from '@ngrx/store';
import { AppState } from '../models/app.state';
import { selectTickets } from '../store/ticket.reducers';
import * as ticketActions from '../store/ticket.actions';

@Component({
  selector: 'app-tickets',
  templateUrl: './tickets.component.html',
  styleUrls: ['./tickets.component.css']
})
export class TicketsComponent implements OnInit {

  tickets$: Observable<Ticket[]>;
    constructor(private store: Store<AppState>) {
        this.tickets$ =  this.store.select(pipe(selectTickets));
       
  }

  ngOnInit() {
  this.store.dispatch(new ticketActions.loadTicketsAction());
     
    this.tickets$.pipe(
      // Getting tickets as undefined
      tap(tickets => console.log('Store Tickets', tickets)),
      map((data) => {
        if (data && data !== null) {
          data[6].assignee = '<a href="javascript:void(0);" class="btn btn-link">John Mike</a>';
         
          return data;
        }
      }),
      catchError(error => {
        return of([]);
      })
    ).subscribe(tickets => {
      console.log('Store tickets', tickets)
    });
  }

}

app.state.ts

import { Ticket } from '../models/ticket';
export interface AppState {
  readonly tickets: Ticket[];
}

ticket.ts

export interface Ticket {
   id: string;
   applicationName?: string;
   category?: string;
   subject: string;
   description?: string;
   status: string;
   priority: string;
   assignee: string;
   platform?: string;
   dueDate: string;
}

ticket.action.ts

import { Action } from '@ngrx/store';
import * as types from './action.types';
import { Ticket } from '../models/ticket';

export class loadTicketsAction implements Action {
  readonly type = types.LOAD_TICKETS;
}

export class loadTicketsSuccessAction implements Action {
  readonly type = types.LOAD_TICKETS_SUCCESS;
  constructor(public payload: Ticket[]) {}
}

export type Actions =
loadTicketsAction |
loadTicketsSuccessAction;

ticket.reducers.ts

import * as ticketActions from './ticket.actions';
import * as types from './action.types';
import { AppState } from '../models/app.state';


export const initialState: AppState = {
  tickets: []
}

export function TicketReducer(state = initialState, action: ticketActions.Actions):AppState {
    switch(action.type) {
      case types.LOAD_TICKETS_SUCCESS: {
        return {...state, tickets: action.payload };
      }
      
      default:
        return state;
    }
  }

  export const selectTickets = (state: AppState) => state.tickets;

ticket.effects.ts

import { Injectable } from "@angular/core";
import { TicketsService } from "../tickets.service";
import { Effect, Actions, ofType } from '@ngrx/effects';
import { map, mergeMap } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { Action } from '@ngrx/store';
import * as ticketActions from './ticket.actions';
import * as types from './action.types';

@Injectable({
    providedIn: 'root'
})
export class TicketEffects {
    constructor(private ticketsService: TicketsService,
        private actions$: Actions
    ) { }

    @Effect() loadTickets$: Observable<Action> = this.actions$.pipe(
        ofType<ticketActions.loadTicketsAction>(types.LOAD_TICKETS),
        mergeMap(() => this.ticketsService.getAllTickets().pipe(
          map(tickets => { 
              return (new ticketActions.loadTicketsSuccessAction(tickets)) 
          })
        ))
    )
}

1 Ответ

1 голос
/ 03 августа 2020

Кажется, проблема в ваших эффектах. Вы должны отправить действие и не возвращать его. Поэтому вместо:

  map(tickets => { 
              return (new ticketActions.loadTicketsSuccessAction(tickets)) 
          })

сделайте следующее:

  map(tickets => { 
            this.store.dispatch(new ticketActions.loadTicketsSuccessAction(tickets)) 
          })

Также добавьте это в свой селектор и обязательно импортируйте selectTickets $. Если вы хотите получить данные из магазина, вы можете использовать следующий шаблон:

export const selectTicketsState = createFeatureSelector<TicketsState>('tickets');

export const getTickets = (state: AppState) => state.tickets;
export const selectTickets$ = createSelector(selectTicketsState, getTickets);

EDIT:

Хорошо, я изменил ваш stackblitz, чтобы он работал, честно говоря, я сделал много изменений там, чтобы я мог не поместил их все. Многие вещи были сломаны / сделаны неправильно:

https://stackblitz.com/edit/ngrx-demo-ticket-uh4hnw

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

Я также рекомендую пройтись через мой Stackblitz, а затем ваш, чтобы вы могли сравнить и увидеть, что было не так.

Удачи! Рекомендую

...