【问题标题】:Dispatch not changing object in Redux state在 Redux 状态下调度不改变对象
【发布时间】:2020-01-22 17:18:28
【问题描述】:

所以我正在构建一个电子商务应用程序,并且我有两个值存储在 redux 状态中来处理购物车。一个是对象数组,每个对象包含 objectID 和数量的两个键。另一个是包含产品信息的对象,其 objectID 作为键。这是我的操作/调度的代码。

addToCart: (product) => {
        return (dispatch, getState) => {
            const {productQuantity, storeSelected, products, storeKeys} = getState().Ecommerce;
            const UPC = product.UPC;
            let newQuant = 1;
            let newProducts;
            for(var p in productQuantity) {
                if (productQuantity[p].UPC === UPC) {
                    newProducts = products
                    newQuant += productQuantity[p].quantity;
                    productQuantity[p] = ({UPC, quantity: newQuant});
                }
            }
            if (!newProducts) {
                console.log("not found")
                productQuantity.push({UPC, quantity: 1});
                newProducts = {
                    ...products,
                    [UPC]: {
                        ...product,
                        price: product.stores[storeKeys[storeSelected]].price,
                        fromStore: storeKeys[storeSelected],
                    }
                }
            }
            dispatch({
                type: actions.CHANGE_CART,
                products: newProducts,
                productQuantity
            });
        };
    },

动作肯定会运行。接下来是我的减速机。

case actions.CHANGE_CART:
    console.log('This runs')
    console.log(action.products);
    console.log(action.productQuantity);
    return {
        ...state,
        products: action.products,
        productQuantity: action.productQuantity
    };

这也会执行,实际上在检查状态时,productQuantity 会在 state 中更新,但 products 不会。在这一点上,我已经尝试了所有的定义配置,并且正在撕毁我的头发。非常感谢您的帮助。

我可以确认的:

  • 正在将正确的数据分派给减速器。
  • reducer 执行。
  • ProductQuantity 由reducer 正确更新并具有正确的值。

【问题讨论】:

    标签: javascript reactjs redux redux-saga redux-thunk


    【解决方案1】:

    第一个问题是您在调度操作之前改变了现有状态,mutating state is forbidden in Redux:

    const {productQuantity, storeSelected, products, storeKeys} = getState().Ecommerce;
                const UPC = product.UPC;
                let newQuant = 1;
                let newProducts;
                for(var p in productQuantity) {
                    if (productQuantity[p].UPC === UPC) {
                        newProducts = products
                        newQuant += productQuantity[p].quantity;
                        productQuantity[p] = ({UPC, quantity: newQuant});
                    }
                }
    

    此处对productQuantity 的任何更改都会改变 Redux 存储中的现有数据。不要那样做。

    我不太清楚这里的products 是怎么回事,因为逻辑感觉有点混乱。

    我的建议:

    首先,开始使用our new official Redux Toolkit package。它有一个configureStore() 函数,可以自动设置对意外突变的检测,如果你发生突变会抛出错误。

    其次,try to move all this modification logic into your reducer,而不是在动作创建方面这样做。

    第三,使用 Redux Toolkit 的 createSlice API,它使用 Immer 库允许您在 reducer 中编写“变异”逻辑并将其安全地转换为正确的不可变更新结果。

    【讨论】:

    • 听从您的建议,并会报告。非常感谢您的帮助。
    • 处理 Redux 状态不变地解决了这个问题。非常感谢。
    【解决方案2】:

    感谢 markerikson 的回复,我修改了我的操作以不可变地处理 Redux 状态,问题已经解决。这是我的更新操作以供参考。

    addToCart: (product) => {
            return (dispatch, getState) => {
                const {productQuantity, storeSelected, products, storeKeys} = getState().Ecommerce;
                const UPC = product.UPC;
    
                let newQuantity = 1;
                for(var p in productQuantity) {
                    if (productQuantity[p].UPC === UPC) {
                        newQuantity += productQuantity[p].quantity;
                    }
                }
    
                dispatch({
                    type: actions.CHANGE_CART,
                    products: {
                        ...products,
                        [UPC]: {
                            ...product,
                            price: product.stores[storeKeys[storeSelected]].price,
                            fromStore: storeKeys[storeSelected],
                        }
                    },
                    productQuantity: productQuantity
                        .filter((value, index) => value.UPC !== product.UPC)
                        .concat([{UPC, quantity: newQuantity}])
                });
            };
        },
    

    【讨论】:

    • 酷,很高兴听到它。根据我的回答,我的下一个建议是尽可能将更多的逻辑移到 reducer 端。
    • 我也这样做了。再次感谢您所做的一切。
    猜你喜欢
    • 2019-02-20
    • 1970-01-01
    • 2019-02-24
    • 1970-01-01
    • 2016-12-24
    • 2019-01-30
    • 2016-06-27
    • 2018-05-03
    • 2021-07-31
    相关资源
    最近更新 更多