Clone and then mutate approach in redux

2019-07-31 15:56发布

I've been reading stuff on redux for a while. And there is a strange thing for me. In most examples people give, all the copying logic is handled via reducers. I'm using typescript and want to adopt a more class-based approach. But maybe I'm missing something.

Let's say I have a shopping Cart class. Along with cart reducer and cart actions. It looks the following way:

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

}

So, here I'm incapsulating cloning logic in a class.

And in my reducer I would go with the signature:

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

Or, actually, how about simply deep-cloning objects via a universal method, then mutating them and then returning? What's bad about that approach?

2条回答
【Aperson】
2楼-- · 2019-07-31 15:58

You might go this way. After all ... You'll respect the immutability contract needed by Redux architecture.

But I wouldn't recommend you to do that.

Deep cloning is not performant at all. The bigger is your store, the slower will be your app.

Plus, to be honnest I tried this approach with a class : https://github.com/maxime1992/pizza-sync/blob/5212a29ee9be916383f759a3a129f7b580ed32ea/frontend/src/app/shared/state/orders/orders.reducer.ts

And it's not so bad. But I ended up using a simple function.

One thing tho, your actions here won't be typed so you will loose some benefits of Typescript.

Instead of doing that, you should create a class per action, as explained in this talk https://www.youtube.com/watch?v=cyaAhXHhxgk

Also, I've made an ngrx starter that might help you get started : https://github.com/maxime1992/angular-ngrx-starter

查看更多
我命由我不由天
3楼-- · 2019-07-31 16:12

This is considered bad practice for several reasons.

First, keeping class instances in state is discouraged because it will break time-travel debugging. You can do it, but it's not the "right" way.

Second, your class is directly mutating its contents. This will also break time-travel debugging, and result in your connected React components not re-rendering properly.

Third, Redux encourages a more functional approach, not OOP.

You may want to read through my two recent blog posts, The Tao of Redux, Part 1 - Implementation and Intent and The Tao of Redux, Part 2 - Practice and Philosophy, which go into detail on what technical limitations Redux requires and why, why common practices exist for using Redux, and why other approaches may be possible but are not considered idiomatic.

查看更多
登录 后发表回答