首页 > 解决方案 > Angular Ngrx 商店 - store.select('selector name') 预计会返回书籍列表,但它返回一个不可迭代的列表

问题描述

我在这里做错了什么?这是我第一次尝试使用状态管理。

我尝试时的最终输出。从状态中获取它

在此处输入图像描述

减速器:

import {createReducer, on} from '@ngrx/store';
import {getBooksSuccess} from './book-list.actions';
import {Book} from '../../models/book.model';

const initialState: Array<Book> = [];

export interface BookState {
  bookList: Book[];
}


export const bookReducer = createReducer(
  initialState,
  on(getBooksSuccess, (state, action) => {
    return {
      ...state,
      books: action,
    };
  })
);

export function BookReducer(state, action) {
  return bookReducer(state, action);
}

行动:

import {createAction} from '@ngrx/store';
import {Book} from '../../models/book.model';


export const FETCH_BOOKS_START = '[Books] books start';
export const FETCH_BOOKS_SUCCESS = '[Books] books Success';


export const getBooks = createAction(
  FETCH_BOOKS_START
);

export const getBooksSuccess = createAction(
  FETCH_BOOKS_SUCCESS,
  (books: ReadonlyArray<Book>) => books
);

影响:

fetchBooks$ = createEffect(() => {
  return this.actions$.pipe(
    ofType(getBooks),
    mergeMap(() => {
      return this.bookService.getBooks().pipe(
        map((bookList) => {
          this.books = this.bookService.mapToBooksModel(bookList);
          return getBooksSuccess(this.books);
        })
      );
    })
  );
});

服务等级

@Injectable({
  providedIn: 'root',
})
export class BookService {
  responseData: BookResponseData[];
  bookList: Book[];

  constructor(private http: HttpClient) {
  }

  getBooks(): Observable<BookResponseData[]> {
    return this.http.get<BookResponseData[]>(
      `./assets/books.json`,
    );
  }

  mapToBooksModel(books: BookResponseData[]) {
      this.bookList = books;
      return this.bookList;
    }
}

模型类

export interface Book {
  id: string;
  name: string;
  author: string;
}

export interface BookResponseData {
  id: string;
  name: string;
  author: string;
}

选择器:

import {BookState} from './book-list.reducer';
import {Book} from '../../models/book.model';
import {createSelector} from '@ngrx/store';

export const BOOK_STATE_NAME = 'bookList';


export const bookSelector = createSelector(
  (state: BookState) => state.bookList,
  (books: Array<Book>) => books
);

export class BookListComponent implements OnInit {

  book$: Observable<Book[]>;
  books: Book[];

  constructor(private store: Store<BookState>) {

  }

  ngOnInit(): void {
   this.store.dispatch(getBooks());
   this.store.select(bookSelector).pipe().subscribe( books => {
      this.books = books;
      console.log(this.books);
    });
  }

标签: angulartypescriptselectorngrx-store

解决方案


我想错误就在这里。您正在为 books 属性分配一个操作对象,但您只需要它的有效负载。您可以像这样分配它,也可以books: action.books简单地解构操作对象。

export const bookReducer = createReducer(
  initialState,
  on(getBooksSuccess, (state, { books }) => {
    return {
      ...state,
      books
    };
  })
);

编辑:再次阅读您的问题时,我注意到可能值得解决的多个潜在问题。

// BookService
getBooks(): Observable<BookResponseData[]> {
  return this.http.get<BookResponseData[]>(`./assets/books.json`)
    .pipe(map(books) => {
      this.bookList = books.map(b => {...b}); //create a copy, otherwise some weird reference issues might pop up
      return this.bookList;
    });
}
// no need for 'mapToBooksModel' function now

你的行为是以一种奇怪的方式定义的。我以前没见过,试试这个。

// books action
export const getBooksSuccess = createAction(
  FETCH_BOOKS_SUCCESS,
  props<{books: ReadonlyArray<Book>}>() // defines payload, books should be then accessible
);

你的效果还需要一些润色。为什么要将服务的结果存储在类属性 ( this.books) 中。这可能会导致一些问题,当严格模式关闭时,您可以在不使用减速器的情况下重写状态。另外,getBooksSuccess函数中发生了什么?

fectchBooks$ = createEffect(() => 
  this.actions$.pipe(
    ofType(getBooks),
    concatMap(() => this.bookService.getBooks())
    map((bookList) => getBooksSuccess(bookList))
  )
);

推荐阅读