【发布时间】:2021-05-17 21:11:39
【问题描述】:
我是 NgRx 和 Firebase 的新手,当我使用 @ngrx/effects 从 Firestore 获取卡片数据时,卡片列表没有显示在卡片列表页面上。但是当我通过新卡片组件表单添加新卡片时,它会显示在页面上,虽然它不会在页面刷新后显示。
我注意到有趣的事情是,当我查看 Redux 开发工具时,它会显示带有数据的卡片操作 (Image),而状态中没有任何数据。如果我添加一张新卡,它的状态会一直保持数据,直到我刷新页面。 (Image2)
下面是我的代码:
card-list.component.html
<mat-card id="addCard">
<button mat-flat-button class="card__like" (click)="add()">
<mat-icon>add_box</mat-icon>
</button>
</mat-card>
<mat-card *ngFor="let card of cards$ | async">
<mat-card-content>
<span class="card__title">{{ card.title }}</span>
<span class="card__text">{{ card.description }}</span>
</mat-card-content>
<mat-card-footer>
<button mat-flat-button class="card__edit" [routerLink]="['/info', card.id]">
<mat-icon>edit</mat-icon>
</button>
<button mat-flat-button class="card__like" (click)="addToFavorite(card.cardId)">
<mat-icon [class.liked]="isLiked(card.cardId)">favorite</mat-icon>
</button>
</mat-card-footer>
</mat-card>
card-list.component.ts
import { Component, OnInit } from '@angular/core';
import { AngularFireDatabase } from '@angular/fire/database';
import { AngularFirestore } from '@angular/fire/firestore';
import { Router } from '@angular/router';
import { Observable } from 'rxjs';
import { map, take, tap } from 'rxjs/operators';
import { select, Store } from '@ngrx/store';
import { Card } from '../card';
import * as fromCard from '../store/reducer/card.reducer';
import * as actions from '../store/action/card.actions';
import * as selectors from '../store/selector/card.selectors';
import { CardService } from '../services/card.service';
import { LikeService } from '../services/like.service';
import { LoadingService } from '../services/loading.service';
@Component({
selector: 'card-list',
templateUrl: './card-list.component.html',
styleUrls: ['./card-list.component.sass'],
})
export class CardListComponent implements OnInit {
cards: Card[] = [];
cards$: Observable<Card[]>;
constructor(private router: Router,
private cardService: CardService,
private likeService: LikeService,
private loadingService: LoadingService,
private afs: AngularFirestore,
private db: AngularFireDatabase,
private store: Store<fromCard.State>) {
this.cards$ = this.store.select<Card[]>(selectors.selectAll).pipe(
tap((_) => console.log(_)),
);
}
ngOnInit() {
this.getCardsFromRealtimeDB('Descending');
}
... some code
public getCardsFromRealtimeDB(sortOrder: string) {
this.store.dispatch(new actions.Query());
}
... some code
}
card.effects.ts
import { Injectable } from '@angular/core';
import { Observable, from as fromPromise } from 'rxjs';
import { switchMap, mergeMap, map } from 'rxjs/operators';
import { Action } from '@ngrx/store';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore';
import { Card } from '../../models/card';
import * as cardActions from '../action/card.actions';
@Injectable()
export class CardEffects {
@Effect()
query$: Observable<Action> = this.actions$.pipe(
ofType(cardActions.QUERY),
switchMap((action) => {
console.log(action);
return this.afs.collection<Card>('cards').stateChanges();
}),
mergeMap((actions) => actions),
map((action) => {
return {
type: `[Card] ${action.type}`,
payload: {
id: action.payload.doc.id,
...action.payload.doc.data(),
},
};
}),
);
@Effect()
edit$: Observable<Action> = this.actions$.pipe(
ofType(cardActions.EDIT_CARD),
map((action: cardActions.EditCard) => action),
switchMap((data) => {
const ref = this.afs.doc<Card>(`card${data.id}`);
return fromPromise(ref.update(data.changes));
}),
map(() => new cardActions.Success()),
);
@Effect()
delete$: Observable<Action> = this.actions$.pipe(
ofType(cardActions.DELETE_CARD),
map((action: cardActions.DeleteCard) => action),
switchMap((data) => {
const ref = this.afs.doc<Card>(`card${data.id}`);
return fromPromise(ref.delete());
}),
map(() => new cardActions.Success()),
);
constructor(private actions$: Actions,
private afs: AngularFirestore) {}
}
card.reducer.ts
import { EntityState, createEntityAdapter } from '@ngrx/entity';
import * as CardActions from '../action/card.actions';
import { Card } from '../../models/card';
export const cardAdapter = createEntityAdapter<Card>();
export type Action = CardActions.All;
export interface State extends EntityState<Card> {}
export const initialState: State = cardAdapter.getInitialState();
export function cardReducer(state: State = initialState, action: Action) {
console.log(action.type, state);
switch (action.type) {
case CardActions.ADD_CARD:
return cardAdapter.addOne(action.payload, state);
case CardActions.EDIT_CARD:
return cardAdapter.updateOne({
id: action.id,
changes: action.changes,
}, state);
case CardActions.DELETE_CARD:
return cardAdapter.removeOne(action.id, state);
default:
return state;
}
}
card.actions.ts
import { Action } from '@ngrx/store';
import { Card } from '../../models/card';
export const ADD_CARD = '[Card] Add Card';
export const GET_ALL_CARDS = '[Card] Get All Cards';
export const EDIT_CARD = '[Card] Edit Card';
export const DELETE_CARD = '[Card] Delete Card';
export const QUERY = '[Card] Query cards';
export const ADDED = '[Card] Added';
export const EDITED = '[Card] Edited';
export const DELETED = '[Card] Deleted';
export const SUCCESS = '[Card] Success';
export class AddCard implements Action {
readonly type = ADD_CARD;
constructor(public payload: Card) {}
}
export class GetAllCards implements Action {
readonly type = GET_ALL_CARDS;
constructor(public payload: Card[]) {}
}
export class EditCard implements Action {
readonly type = EDIT_CARD;
constructor(public id: number,
public changes: Partial<Card>) {}
}
export class DeleteCard implements Action {
readonly type = DELETE_CARD;
constructor(public id: number) {}
}
export class Query implements Action {
readonly type = QUERY;
constructor() {}
}
export class Added implements Action {
readonly type = ADDED;
constructor(public payload: Card) {}
}
export class Edited implements Action {
readonly type = EDITED;
constructor(public payload: Card) {}
}
export class Deleted implements Action {
readonly type = DELETED;
constructor(public payload: Card) {}
}
export class Success implements Action {
readonly type = SUCCESS;
constructor() {}
}
export type All
= AddCard
| GetAllCards
| EditCard
| DeleteCard
| Query
| Added
| Edited
| Deleted
| Success
【问题讨论】:
-
请包括任何进一步的调试步骤。
tap((_) => console.log(_)在上面的代码中为您提供了cards$可观察的内容,这是您所期望的吗? QUERY 的结果是什么(为什么不是 GetAllCards?),这是否反映在状态中? -
@AndrewAllen,
tap((_) => console.log(_)我想看看是否有任何数据,但我得到的是空数组。 GetAllCards 是我忘记删除的代码中未使用的部分,它可能暗示与 Query 相同的逻辑。查询返回卡片数据,该数据不反映在状态中。 -
我在你的减速器中看不到
GET_ALL_CARDS的动作,你需要像cardAdaptor.setAll()这样的东西
标签: angular firebase google-cloud-firestore ngrx