Как мы храним результаты отправки в переменных внутри наших действий? - PullRequest
2 голосов
/ 14 апреля 2020

Мне нужно обработать довольно простую логику c внутри моего состояния, и мне действительно трудно собрать воедино то, что нужно сделать, и в данный момент я не могу понять, как сохранить результаты действия в переменной. Например, выполните следующее действие:

@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));
        }
    }

Я получаю ошибки от этой функции, сообщая, что

тип void не может быть присвоен номеру типа

в отношении установки результатов для переменных getCategory и getProduct.

В целом я пытаюсь сделать следующее:

    1. Поиск внутри соответствующая категория государства для продукта.
  • Если данные о продукте существуют, установите для свойства «текущий продукт» данные о состоянии.

или

  • 3a. Если продукт не существует, отправьте запрос API бэкэнду.
  • 3b. Установите данные продукта как «текущий продукт».
  • 3 c. Добавить данные в список «продукты» в соответствующей категории внутри штата.

способ, которым я настраиваю другие свои функции, выглядит следующим образом

@Action(InitProductState)
    public initProductState(ctx:StateContext<ProductDataModel>){
        //console.log('InitProductState triggered');
        if(ctx.getState().categories.length < 1){
            //console.log('if condition triggered');

            return this.dataService.fetchProductInitData().pipe(tap((result) =>{

                //console.log('data service triggered');

                const categoryList: ProductCategoryModel[] = [];

                result.forEach(a=>{
                    const categoryObj: ProductCategoryModel = {
                        productCategoryId: a.productCategoryId,
                        name: a.name,
                        description: a.description,
                        products: []
                    };

                    categoryList.push(categoryObj);
                });
                ctx.patchState({ categories:[...categoryList]});
                //console.log(ctx.getState());
            }));
        }
    }

    @Action(FindCategory)
    private searchForCattegory(ctx:StateContext<ProductDataModel>, {category}: FindCategory):number{
        return ctx.getState().cattegories.findIndex(a=>a.productCattegoryId === category) as number;
    }

    @Action(FindProduct)
    private searchForProduct(ctx:StateContext<ProductDataModel>, {category, product}: FindProduct): number{
        return ctx.getState().cattegories[category].products.findIndex(a=> a.productId === product) as number;
    }

    @Action(SetCurrentProduct)
    private setCurrentProduct(ctx:StateContext<ProductDataModel>, {category, product}: SetCurrentProduct){
        ctx.setState((state:ProductDataModel)=>{
            state.currentProduct = state.cattegories[category].products[product];
            return state;
        });
    }

    @Action(FetchItem)
    private fetchProductData({category, product}: FetchItem){
        return this.dataService.fetchProductData(category, product);
    }

    @Action(FetchProduct)
    public fetchProduct(ctx:StateContext<ProductDataModel>, {cattegory, product}: FetchProduct){
        const state = ctx.getState();

        if(state.cattegories.length < 1){ ctx.dispatch(new InitProductState()); }

        ctx.dispatch(new HandleProduct(cattegory, product));
    }

Я не получаю никаких ошибки в отношении любого из них, но я просто подумал, что покажу, как все настроено, только если что-то не так. Единственное решение, которое я могу придумать, - это создание переменных в состоянии и использование селекторов для их просмотра, но это похоже на крайнее излишество для чего-то, на что мне просто нужно сослаться в одном действии, плюс то, что я узнал до сих пор, используя состояние для таких вещей действительно не предлагается. Как я могу настроить это на работу?

Для более глубокого понимания формы моего состояния вот мои интерфейсы.

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;
}

1 Ответ

1 голос
/ 14 апреля 2020

Если вы упростите эту задачу, вам может показаться, что с ней немного легче управлять.

Есть несколько изменений, которые вы могли бы рассмотреть:

  1. Потеряйте действия для FindXXX и просто захватывайте их непосредственно из текущего состояния, а не отправляйте Action.
  2. . Затем сразу же сделайте исправление, если найдете продукт, в противном случае вызовите API, чтобы получить его, а затем исправьте его в состояние.

См. Пример ниже (адаптировано из вашего примера кода).

    @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 
                       });
                    })
                  );
        }));
    }
Для начальной загрузки данных, т. Е. InitProductState, либо загрузите это, используя ловушку жизненного цикла ngxsOnInit, либо запустите это с помощью некоторого Action, который отправляется, когда требуются данные (обычно, когда эта страница загружается / перемещается). to).

Пример кода, который я добавил, который вы видите, немного неуклюж, чтобы попытаться исправить изменения вложенного значения продукта в списке категорий. Некоторое время назад я обнаружил, что с помощью NGXS можно избежать этих вложенных структур, что облегчит разработку.

Возможно, вы захотите еще больше упростить структуру модели состояния, чтобы список продуктов был коллекция верхнего уровня (такая же как категории) (даже если ваш API возвращает ее вложенным). Затем, когда вы обновляете / добавляете продукт, вы можете исправлять простой массив, а не вложенный структурированный. Это сделает ваш код действия редактирования / исправления намного проще для поддержания неизменного состояния. Вы можете использовать Selectors, если хотите сгруппировать / отфильтровать данные до того, как они будут использованы компонентами Angular.

...