Angular 注销时重置状态

Angular 注销时重置状态,angular,rxjs,Angular,Rxjs,在我的购物车服务中,我想重置状态树,例如当用户注销时。我怎样才能做到这一点?闪电战操场 导出接口状态树{ 门店:CartItem[]; 购物车:CartItem[]; 总数:, 校验:布尔; }; 我的变量 private stateTree$=new BehaviorSubject(null); private checkoutTrigger$=新行为主体(false); 私有cartAdd$=新主题(); 私有cartRemove$=新主题(); 我的状态 state$:Observab

在我的购物车服务中,我想重置状态树,例如当用户注销时。我怎样才能做到这一点?闪电战操场

导出接口状态树{
门店:CartItem[];
购物车:CartItem[];
总数:,
校验:布尔;
};
我的变量

private stateTree$=new BehaviorSubject(null);
private checkoutTrigger$=新行为主体(false);
私有cartAdd$=新主题();
私有cartRemove$=新主题();
我的状态

state$:Observable=this.stateTree$.pipe(
switchMap(()=>this.getItems().pipe(
CombineTest([this.cart$、this.total$、this.checkoutTrigger$]),
去BounceTime(0),
)),
map([store,cart,tot,checkout]:any)=>({store,cart,tot,checkout}),
点击(状态=>{
if(state.checkout){
console.log('checkout',state);
}
}),
//确保我们与全世界共享!或者只共享整个应用程序
共享重播(1)
);
需要解决的问题 我认为这里有两个单独的问题需要解决

  • “重置”状态树意味着什么?默认状态是什么
  • 注销是如何发生的,我们如何将该事件转化为应用程序“状态”的变化
  • 重置意味着什么? 求解1的常用方法是定义产生默认/初始状态的函数:

    导出函数createInitialStateTree():StateTree{ 返回{ 门店:[]; 购物车:[]; 总数:{ 小计:0; 税项:0 ;; grandTot:0; }, 签出:假; } } 然后,当您要重置应用程序状态时,将该函数的结果分配到存储应用程序状态的位置(
    BehaviorSubject
    ):

    this.stateTree$.next(createInitialStateTree());
    
    如何在注销时执行重置? 至于2,我们不希望将应用程序状态直接公开给消费者,以便他们以任何方式进行更改,因此在服务中保持
    stateTree$
    private
    是一个很好的第一步

    但我们确实希望允许应用程序的其他部分以我们定义的非常具体的方式更改状态

    这意味着在服务上创建一个方法,该方法要么接受用于计算状态更改的参数,要么只是一个不接受导致状态更改的非常特定的副作用的参数的方法

    我认为这些选项中的第二个对于在这里“注销”最有意义

    向您的
    ShoppingCartService
    添加一个方法以公开“重置”状态更改:

    resetCart(){
    this.stateTree$.next(createInitialStateTree());
    }
    
    并在用户注销后调用此方法:

    //在应用程序的其他部分
    签出(){
    这个.http.post('/api/signout').pipe(
    点击(()=>this.shoppingCartService.resetCart())
    )
    .subscribe();
    }
    
    在您的页面中,我为您添加了一个注销按钮,该按钮在您的服务中只是一个私人注销$subject

    重构的私有get cart$

      private get cart$(): Observable<CartItem[]> {
        const addOperation = (item) => (acc) => [...acc, item];
        const removeOperation = (item) => (acc) => [...acc.filter(i => i.uuid !== item.uuid)];
        const resetOperation = () => (acc) => [];
    
        return merge(
          this.cartAdd$.pipe(map(addOperation)),
          this.cartRemove$.pipe(map(removeOperation)),
          this.logout$.pipe(map(resetOperation))
        ).pipe(
          scan((acc, fn) => fn(acc), []),
          startWith([])
        );
      }
    
    private get cart$():可观察{
    const addOperation=(项目)=>(acc)=>[…acc,项目];
    const removeOperation=(item)=>(acc)=>[…acc.filter(i=>i.uuid!==item.uuid)];
    常量重置操作=()=>(acc)=>[];
    返回合并(
    此.cartAdd$.pipe(映射(addOperation)),
    此.cartRemove$.pipe(映射(removeOperation)),
    此.logout$.pipe(映射(重置操作))
    ).烟斗(
    扫描((acc,fn)=>fn(acc),[]),
    startWith([]))
    );
    }
    
    扫描前,状态突变应用于obersvables。此机制允许您避免在扫描本身中筛选特定操作。就像您以前所做的那样,请求
    if(item.remove){…}else{…}
    。现在,您可以轻松地创建更多的状态突变并向其添加特定的函数,而无需扩大接口


    仅供参考:我还在你的私人网站get total$中进行了一次快速的小重构。不需要调整它。我只是觉得这样更好。

    这取决于注销的调用方式。清除上面的观察值可能是一个副作用,当用户注销时会调用它。Great Mate!:)