在 redux 中克隆然后变异方法

Clone and then mutate approach in redux

我已经阅读了一段时间关于 redux 的资料。对我来说有一件奇怪的事。在人们给出的大多数示例中,所有复制逻辑都是通过 reducer 处理的。 我正在使用打字稿,并希望采用更多基于 class 的方法。但也许我遗漏了什么。

假设我有一个购物车class。连同推车减速器和推车动作。 它看起来如下所示:

export class Cart
{
    private items:{[key:string]:number} = {};

    constructor(items:{[key:string]:number} = {})
    {
        Object.assign(this.items, items);
    }

    public addItem(id:string)
    {
        this.items[id] = this.items[id]?this.items[id]+1:1;
    }

    public removeItem(id:string)
    {
        this.items[id]--;

        if(this.items[id] <= 0)
        {
            delete this.items[id];
        }

    }

    public setItemsCount(id:string, count:number)
    {
        this.items[id] = count;
    }

    public clone():Cart
    {
        return new Cart(Object.assign({}, this.items));
    }

}

所以,我在这里将克隆逻辑封装在 class 中。

在我的减速器中,我会使用签名:

function reducer(state = new Cart(), action:Action): Cart {
    //first clone, then mutate, then return
}

或者,实际上,通过通用方法简单地深度克隆对象,然后变异它们然后返回怎么样?这种方法有什么不好?

由于多种原因,这被认为是不好的做法。

首先,不鼓励将 class 个实例保持在状态 because it will break time-travel debugging。你 可以 做到,但这不是 "right" 的方式。

其次,您的 class 直接改变了它的内容。这也将打破时间旅行调试,result in your connected React components not re-rendering properly.

第三,Redux 鼓励更实用的方法,而不是 OOP。

您可能想通读我最近的两篇博文,The Tao of Redux, Part 1 - Implementation and Intent and The Tao of Redux, Part 2 - Practice and Philosophy,其中详细介绍了 Redux 需要哪些技术限制及其原因,为什么存在使用 Redux 的常见做法,以及为什么可能有其他方法可能但不被认为是地道的。

你可以走这条路。毕竟......你会尊重 Redux 架构所需的不变性契约。

但我不建议你这样做。

深度克隆根本不高效。您的商店越大,您的应用程序就越慢。

另外,老实说,我用 class 尝试了这种方法: https://github.com/maxime1992/pizza-sync/blob/5212a29ee9be916383f759a3a129f7b580ed32ea/frontend/src/app/shared/state/orders/orders.reducer.ts

而且还不错。但我最终使用了一个简单的函数。

有一件事,你的 actions 这里不会被打字,所以你会失去 Typescript 的一些好处。

您应该为每个操作创建一个 class,而不是这样做,如本演讲中所述 https://www.youtube.com/watch?v=cyaAhXHhxgk

此外,我制作了一个 ngrx 启动器,可以帮助您入门:https://github.com/maxime1992/angular-ngrx-starter