在 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
我已经阅读了一段时间关于 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