Angular 我们如何将分派结果存储到操作中的变量?

Angular 我们如何将分派结果存储到操作中的变量?,angular,typescript,ngxs,immer.js,Angular,Typescript,Ngxs,Immer.js,我需要在我的状态中处理一些非常简单的逻辑,我很难把需要做的事情拼凑在一起,现在我不知道如何将一个操作的结果存储在一个变量中。以下面的操作为例 @Action(HandleProduct) private handleProduct(ctx:StateContext<ProductDataModel>, {category, product}: HandleProduct){ let getCategory: number; let getPr

我需要在我的状态中处理一些非常简单的逻辑,我很难把需要做的事情拼凑在一起,现在我不知道如何将一个操作的结果存储在一个变量中。以下面的操作为例

@Action(HandleProduct)
    private handleProduct(ctx:StateContext<ProductDataModel>, {category, product}: HandleProduct){

        let getCategory: number;
        let getProduct:  number;

        ctx.dispatch(new FindCategory(category)).pipe(tap(result => getCategory = result));
        ctx.dispatch(new FindProduct(getCategory, product)).pipe(tap(result => getProduct = result));



        if(getProduct !== -1){ ctx.dispatch(new SetCurrentProduct(getCategory, getProduct)); }

        else{

            ctx.dispatch(new FetchProduct(category, product)).pipe(tap(result => {
                ctx.setState((state: ProductDataModel)=>{
                    state.cattegories[getCategory].products.push(result);
                    return state;
                });
            }));

            ctx.dispatch(new FindProduct(getCategory, product)).pipe(tap(result => getProduct = result));
            ctx.dispatch(new SetCurrentProduct(getCategory, getProduct));
        }
    }
在这些方面我没有发现任何错误,但我只是想展示一下它是如何设置的,以防有什么问题。我能想到的唯一解决方案是在状态上创建变量,并使用选择器查看它们,但对于我只需要在一个操作中引用的东西来说,这感觉太过分了,再加上我到目前为止所学到的,不建议将状态用于这类事情。我怎样才能让它工作

为了更深入地了解我的状态,这里是我的接口

export interface ShortDescriptionCore  { description       : string; }
export interface ProductIdCore         { productId         : string; }
export interface ProductCategoryIdCore { productCategoryId : string; }
export interface InstructionTargetCore { instructionKey    : string; }
export interface NameCore              { name              : string; }


export interface ProductDataItem extends ProductIdCore, NameCore, ShortDescriptionCore, InstructionTargetCore{
    models: ModelDataItem[];
}

export interface ProductCategoryItem extends ProductCategoryIdCore, NameCore, ShortDescriptionCore{}

export interface CategoryInitIndex extends ProductCategoryIdCore{ products?: ProductDataItem[]; }

export interface ProductCategoryModel extends ProductCategoryItem{ products: ProductDataItem[]; }

export interface ProductDataModel{
    categories: ProductCategoryModel[];
    currentProduct: ProductDataItem;
}

如果你简化一下,你可能会发现它更容易管理

您可能会考虑进行一些更改:

  • 丢失
    FindXXX
    的操作,直接从当前状态抓取它们,而不是分派
    操作
  • 然后,如果找到产品,请立即进行修补,否则请调用API获取该产品,然后将其修补到状态
  • 请参见下面的示例(改编自您的代码示例)

    @操作(HandleProduct)
    handleProduct(ctx:StateContext,{category,product}:handleProduct){
    const currentState=ctx.getState();
    //直接在当前状态下搜索(不需要为此分派操作)
    const categoryMatch=currentState.categories.find(cat=>cat.productCategoryId==category);
    const productMatch=categoryMatch.products.find(p=>p.productId==product);
    //找到了一个产品,所以要使用它
    如果(productMatch){
    patchState({currentProduct:productMatch});
    }
    否则{//没有匹配项,所以请获取它
    返回此.dataService.fetchProduct(类别,产品)
    .烟斗(
    轻触(结果=>{//添加产品并标记为当前
    //需要更新正确的类别产品列表(深度克隆)
    const updatedCategories=[…categories];
    const index=updateCategories.findIndex(cat=>cat.productCategoryId==category);
    updatedCategories[index]。产品=[…updatedCategories[index]。产品,结果];
    //修补程序更新产品列表和当前产品。
    ctx.patchState({
    类别:更新的类别,
    当前产品:结果
    });
    })
    );
    }));
    }
    
  • 对于数据的初始加载,即
    InitProductState
    ,可以使用
    ngxsOnInit
    生命周期钩子加载数据,也可以通过一些
    操作触发数据,这些操作在需要数据时(通常在加载/导航到该页面时)被调度
  • 您可以看到,我添加的示例代码在尝试修补类别列表中嵌套产品值的更改时有点笨拙。我发现使用NGXS已经有一段时间了,如果可以避免这些嵌套结构,那么开发就会更容易


    您可能需要考虑进一步扁平化您的状态模型结构,以便产品列表是顶级集合(与类别相同)(即使您的API返回嵌套)。然后,当您更新/添加产品时,您可以修补一个简单的数组,而不是嵌套的结构化数组。它将使您的编辑/修补操作代码更易于维护不可变状态。如果要在数据被角度分量消耗之前对其进行分组/过滤,可以使用

    选择器。

    谢谢!!!。我这样做的原因是,每种产品都有多种型号和尺寸,而且会不断增长。除此之外,我遇到的每一个例子和教程都是如此简单和基本,以至于我不知道如何以更复杂的方式使用它。或者像你建议的那样把它弄平会把一切都变成一场噩梦,我最终无法跟踪。你知道有没有什么例子可以展示如何以扁平化的方式完成如此复杂的事情,因为我很想研究它,看看用什么模式和功能来完成这样的事情。好的,我在
    updatedCategories[index].products=[…]上遇到了一个错误
    零件导致错误,说明
    无法分配给对象“[object object]”的只读属性“products”
    .G“day-是的,我的示例代码不是100%完美,在发布此答案时无法测试它。您需要在
    updatedCategories[index]
    处深度克隆对象,以便修改克隆并将其推回到状态。在我看来,您会发现更平坦的结构更易于处理(即使它一开始似乎违反直觉,特别是如果您的API返回嵌套的父/子结构)。在我当前的应用程序中,我们有几十个状态,任何我们没有平坦化的地方(我们早期的一些代码),都很难继续保持下去。如果您可以编辑您的问题以包括状态模型(以显示此模型/大小等),那么我可能可以添加更多的指针确定我在其他问题上被困了几天,因为此解决方案不知何故导致了我的
    @Selector()
    将以前的和当前的数据都返回到我的组件,而我一辈子都无法弄清楚发生这种情况的原因。
    export interface ShortDescriptionCore  { description       : string; }
    export interface ProductIdCore         { productId         : string; }
    export interface ProductCategoryIdCore { productCategoryId : string; }
    export interface InstructionTargetCore { instructionKey    : string; }
    export interface NameCore              { name              : string; }
    
    
    export interface ProductDataItem extends ProductIdCore, NameCore, ShortDescriptionCore, InstructionTargetCore{
        models: ModelDataItem[];
    }
    
    export interface ProductCategoryItem extends ProductCategoryIdCore, NameCore, ShortDescriptionCore{}
    
    export interface CategoryInitIndex extends ProductCategoryIdCore{ products?: ProductDataItem[]; }
    
    export interface ProductCategoryModel extends ProductCategoryItem{ products: ProductDataItem[]; }
    
    export interface ProductDataModel{
        categories: ProductCategoryModel[];
        currentProduct: ProductDataItem;
    }
    
        @Action(HandleProduct)
        handleProduct(ctx:StateContext<ProductDataModel>, {category, product}: HandleProduct){
    
        const currentState = ctx.getState();
    
        // Search directly in current state (don't need to dispatch Actions for this)
        const categoryMatch = currentState.categories.find(cat => cat.productCategoryId === category);
        const productMatch = categoryMatch.products.find(p => p.productId === product); 
    
        // Found a product, so use it
        if(productMatch){ 
           ctx.patchState({ currentProduct: productMatch });
        }
        else { // No match, so fetch it
           return this.dataService.fetchProduct(category, product)
                  .pipe(
                     tap(result => { // Add product and flag as current
                         // Need to update the correct category product list (deep clone)
                         const updatedCategories= [...categories];
                         const index = updateCategories.findIndex(cat => cat.productCategoryId === category);
                                                   updatedCategories[index].products = [...updatedCategories[index].products, result];
                         // Patch update the product list and the current product.
                         ctx.patchState({ 
                             categories: updatedCategories,
                             currentProduct: result 
                           });
                        })
                      );
            }));
        }