Ngrx 存储 take(1),但在注销/登录后重置

Posted

技术标签:

【中文标题】Ngrx 存储 take(1),但在注销/登录后重置【英文标题】:Ngrx store take(1), but reset after logout/login 【发布时间】:2021-11-02 08:15:45 【问题描述】:

所以,假设您有一个带有书籍列表的 ngrx 商店。

当您登录到您的个人资料页面时,您可以使用以下方式获取您的图书:

this.store.dispatch(getBooks());

哪个会触发效果:

  getBooks$ = createEffect(() =>                                                                 
    this.actions.pipe(                                                                         
      ofType(A.getBooks),                                                                        
      switchMap(() =>                                                                          
        this.bookService.getBooks().pipe(                                                        
          map((books) => A.getBooksOk( books )),                                                                                  
          catchError(() => EMPTY),
        ),                                                                                     
      ),                                                                                       
    ),                                                                                         
  ); 

但是,您不希望每次导航到个人资料页面时都触发此效果,因为您只需要获取图书一次。

所以你添加take(1):

  getBooks$ = createEffect(() =>                                                                 
    this.actions.pipe(                                                                         
      ofType(A.getBooks),
      take(1),                                                                        
      switchMap(() =>                                                                          
        ...

现在的问题是,如果您注销然后登录到另一个配置文件,则商店将不会获取您的图书,因为该效果已由先前的配置文件触发。

对此的明显解决方案是不使用take(1),而是在商店中设置另一个变量booksLoaded,您可以使用它来检查您是否应该得到这些书。

但是,这非常乏味,因为您需要为存储中的每个变量使用这些“加载”变量之一,并添加一堆额外的代码来管理这些变量。

所以,问题是:有没有办法让效果只触发一次(如take(1)),但是当您注销并重新登录时,您允许效果再次触发(只触发一次)?

编辑: 您也可以只检查效果中是否未定义书籍。 但是,在您从服务器获得响应之前,仍然可能会多次触发该效果,因此它并不总是有效。

【问题讨论】:

IMO 标记数据是否已加载的策略是一个非常好的策略,因为它可以让您更好地控制注销/登录问题。在注销操作+reducer 中,您将清除该标志,并且将为新登录的用户重新加载数据。这比拥有take(n) 的效果要好得多,否则应该保持活力。该标志也可以是一个日期戳,以便您可以确定它是否过时并需要刷新。不要担心 - 我认为这是一个不错的选择 :) 【参考方案1】:

我不知道您为什么认为仅检查您是否已有数据很麻烦。您不一定需要新变量,只需检查您的结果是否已设置。

getBooks$ = createEffect(() =>
  this.actions.pipe(
    ofType(A.getBooks),
    withLatestFrom(this.store.select(S.selectBooks)),
    exhaustMap(([, books]) =>
      iif(
        () => books,
        of(A.getBooksOk( books )),
        this.bookService.getBooks().pipe(
          map((books) => A.getBooksOk( books )),
          catchError(() => EMPTY),
        ),
      ),
    ),
  ),
);

只要确保在有意义的地方(例如注销时)清除减速器中的书籍即可。

【讨论】:

如果在从服务器接收到数据之前多次调用“this.store.dispatch(getBooks())”,这将不起作用。不是说这应该经常发生,只是这不是万无一失的。 当然该操作可能会启动多次,但它只会调用this.bookService.getBooks()iff您商店中的书籍未设置。如果书籍已经被检索,它会立即返回。 我们实际上是在做:if I already have the books, then return the books, otherwise, get the books from the service 当然,这是假设操作 A.getBooksOk 实际上存储了结果,并且将来可以使用选择器 S.selectBooks 访问。 我刚刚重读了您的评论,在这种情况下,您可能希望使用exhaustMap 而不是switchMap。因为exhaustMap 将忽略未来的更新,直到第一次解决。继续类比,if I already have the books, then return the books, otherwise, get the books from the service, but don't bug me until I know for sure

以上是关于Ngrx 存储 take(1),但在注销/登录后重置的主要内容,如果未能解决你的问题,请参考以下文章

如何配置在Django中注销后重定向到哪里?

如何配置在Django中注销后重定向到哪里?

终极会员注销无法使用 WPML

从 ASP.NET MVC 客户端应用程序和 .NET 5 openiddict 服务器注销。注销后重定向 URL 无效

CodeIgniter:动态登录后重定向?

Facebook 登录后重定向到新的 ViewController