关于从 NgRx 存储中选择数据的问题

use*_*244 2 ngrx ngrx-effects angular

@Component({
  selector: 'app-user',
  styleUrls: ['./user.component.css'],
  template: `
    <button (click)="clickSearch('some keyword')">Search</button>

    <div *ngIf="books$ | async as books">

      <h5 *ngIf="hasSearched">No. of books: {{ books.length }}</h5>

      <p *ngIf="hasSearched && !books.length">No books found</p>

      <p *ngIf="!hasSearched">Please enter a search keyword to start searching for books.</p>

      <h2 *ngFor="let book of books">{{ book.title }}</h2>

    </div>
  `
})
export class UserComponent {

  constructor(private store: Store) {}

  hasSearched: boolean = false;

  books$ = this.store.select(BooksSelector.getBooks)
             .pipe(
               tap(data => console.log(data))
             );

  clickSearch(keyword: string) {

    this.hasSearched = true;

    this.store.dispatch(BooksActions.loadBooksFromApi(
      { q: keyword }
    ));

  }
}

Run Code Online (Sandbox Code Playgroud)

假设我有一个简化的 Angular 组件代码,如上所示。流程:

  1. 当我们第一次到达此页面时,store.select() 语句立即从 store 返回初始状态值[]。这将导致模板显示“未找到书籍”和“书籍数量=0”消息,这是我不想要的。因此,为了防止这种情况,我添加了hasSearched布尔属性并显示“请输入...”消息。

  2. 单击“搜索”按钮后,该hasSearched属性将变为true,并且当 API 检索数据时,模板将短暂显示“未找到书籍”和“书籍数量=0”消息。我不希望它这样做。我希望消息能够等待(通过隐藏)直到 API 调用完成。

  3. API调用完成后,书籍列表正常显示在模板中,并且消息正确显示。

  4. 当用户搜索完某些内容并获得一些结果,然后离开页面并返回页面后,store.select() 语句将返回之前的存储值。我不想要这个。我只是希望此页面重新开始,没有书籍列表,只有消息“请输入搜索关键字以开始搜索书籍。”。

我的问题是针对第 2 点和第 4 点:

对于第 2 点,我应该添加另一个布尔属性来检查加载状态吗?似乎 *ngIf 标志太多。有没有更优雅的方法通过 NgRx 选择器来处理这个问题?

对于第 4 点,我如何实现这一目标?是通过[]在 store 中推入一个空来ngOnDestroy()强制清除 Books 状态吗?

Has*_*oin 5

对于点号 2

我建议hasSearched: boolean在您的减速器中添加另一个布尔值,然后hasSearched从组件中删除。订阅hasSearched在组件中使用选择器。当用户第一次输入该组件时,应该是undefined。由此,您可以显示您的消息

   <p *ngIf="(hasSearched | async) === undefined">
       Please enter a search keyword to start searching for books.
   </p>
Run Code Online (Sandbox Code Playgroud)

当用户单击按钮时,您将调度您的操作BooksActions.loadBooksFromApifalse在同一操作/减速器中,当 API 调用正在进行时,将字段 hasSearched 转换为,此false标志将阻止显示这两条消息:

<h5 *ngIf="(hasSearched | async)">No. of books: {{ books.length }}</h5>

<p *ngIf="(hasSearched | async) && !books.length">No books found</p>
Run Code Online (Sandbox Code Playgroud)

直到true完成为止。作为参考,您的状态和减速器将如下所示。

    export interface BooksState {
       books: any;
       hasSearched: boolean;
    }

    export const initialState: BooksState = {
       books: undefined,
       hasSearched: undefined
    };
Run Code Online (Sandbox Code Playgroud)

减速器的情况看起来像这样。

    case BooksActionsTypes.loadBooksFromApi:
      return {
        ...state,
        hasSearched: false
     };

    case BooksActionsTypes.loadBooksFromApiSuccessful:
      return {
        ...state,
        books: action.payload.books
        hasSearched: true
     };
Run Code Online (Sandbox Code Playgroud)

对于点 4

根据我的理解,您的想法是正确的,通过在 上发送操作来清除状态ngOnDestroy()。这与我使用的方式相同,当我想在下次访问同一组件时获得新的状态时,可以清除状态。这将类似于我在下面写的内容

    case BooksActionsTypes.ClearState:
      return {
        ...state,
        books: undefined
        hasSearched: undefined
       };
Run Code Online (Sandbox Code Playgroud)