Angular / Redux 保持状态的正确方式

Angular / Redux correct way to keep the state

我正在使用 Angular + Redux 构建一个购物车应用程序。 我有一个对象数组(Products 在我的购物车中),每个接口:

export interface IProduct {
    id: number;
    description: string;
    isAdded: boolean;
}

页面中的产品有一个按钮加入购物车

<div class="addBtn" (click)="addToCart(prod)">
    <span class="unaddedItem" *ngIf="!prod.isAdded; else added">Add to cart</span>
    <ng-template>
        <span class="addedItem" #added>In cart</span>
    </ng-template>
</div>

我想要的是在添加产品时将 Add to cart 文本更改为 In cart。我用 Rxjs 成功地做到了,但是当我离开 Products 页面然后返回它时,我的 In cart 添加产品的跨度丢失(添加到购物车 再次显示)。所以,我认为 Redux 是帮助我保持状态的唯一方法。

我写了一个带有一些动作的 reducer 函数。这是其中之一:

export function rootReducer(state, action){
    switch(action.type){
        case ADD_PRODUCT:
            action.product.id = state.products.length + 1;
            return Object.assign({}, state, {
                products: state.products.concat(Object.assign({}, action.product))
            })
    }
}

所以,我的问题是 将对象添加到购物车后保持对象状态的正确方法是什么? 我应该为此使用相同的 ADD_PRODUCT 操作还是应该编写另一个操作,例如 MARK_ADDED 并使用它对于另一个添加的对象数组?因此,In cart products 和 Marked added products 有两个不同的数组,我将在其中相应地保留添加的对象及其状态?

首先,我不会将那个逻辑添加到您的 rootReducer 中。 Remember, your reducers mimic the shape of your data。状态应该从您的 rootReducer 流向各个状态片。在下面的示例中,理想情况下,您需要一个 returns 整个状态的 rootReducer。 returns by_id 和 all_ids 的产品和购物车减速器等等,直到构建了整个数据结构。

对于您的购物车和产品,我更倾向于采用以下方式:

{
  products: {
    by_id: {
      1: {
        id: 1,
        name: "hairdryer",
        price: "2.99",
        in_cart: true
      },
      2: {
        id: 2,
        name: "brush",
        price: "299.99",
        in_cart: false
      }
    },
    all_ids: [1, 2]
  },
  cart: {
    products_added: [1],
    saved: false,
    some_data: "foo"
  }
} 

这遵循文档示例中列出的结构。当一个 add_to_cart 动作被调度时,它的对象通过每个 reducer 向下传递,产品将看到这个数据以及购物车。如文档中所示,我只是在产品中的 in_cart reducer 和购物车中的 products_added reducer 中使用 switch 语句。


此外,在减速器中添加 UUID 分配也是一种不好的做法。 reducer 的工作是简单地定义状态如何变化,而不是定义状态是什么。在您的操作或中间件中执行此操作。


我也倾向于通过您的状态传递整个动作,而不是只传递一个键。这样,如果您需要在您的状态下进一步执行操作的另一部分,则无需重构。