我正在开发一个购物车,并且正在尝试解决应用程序中的两个问题:
向商店添加商品会覆盖商店中以前的商品:
初始状态:
const initialState = {
items: {},
showCart: false
};
添加到购物车 reducer :
问题:这适用于将商品添加到购物车,但是当我在购物车中添加另一个商品时,它会覆盖前一个商品。为什么会这样/我如何保留以前状态的项目?
let addToCartState = {...state,
items: {
[action.id]: {
id: action.id,
color: action.product_selection.color,
size: action.product_selection.size,
quantity: 1
}
},
showCart: true
}
return state.merge(addToCartState);
从购物车 reducer 中删除所有内容:
问题:这似乎可行,但我似乎无法从州 map 中获取数据。我似乎无法像在其他州那样调用“state.cart.items”(请参阅mapStateToProps)。
let removeFromCartState = {...state,
items: {
...state.items
},
showCart: true
}
function mapStateToProps(state) {
console.log(state.cart);
console.log("🙃");
return { products: state.products, items: state.cart.items }
}
状态.购物车:
Map {size: 8, _root: ArrayMapNode, __ownerID: undefined, __hash: undefined, __altered: false}
size: 8
__altered: false
__hash: undefined
__ownerID: undefined
_root: ArrayMapNode
entries: Array(8)
0: Array(2)
0: "items"
1: Map
size: 0
...
^ 现在没有项目(大小:0,在上一个 reducer 之后为 1);我现在需要使用 fromJS 之类的东西来解析它还是应该这样做?
编辑-combineReducers:
import {combineReducers} from 'redux';
import app from './appReducer';
import products from './productsReducer';
import cart from './cartReducer';
import user from './userReducer';
export default combineReducers({
app: app,
products: products,
cart: cart,
user: user
});
最佳答案
问题的根源在于您将 Immutable.js 对象视为常规 JavaScript 对象,而不是使用用于您正在执行的任务的内置 Immutable.js 功能。
Problem: This works for adding an item to the cart, but when I go to add another item in the cart, it overwrites the previous item. Why would that be / How do I preserve the items in the previous state?
让我们看一下您的代码:
let addToCartState = { ...state,
items: { [action.id]: { /* ... */ } },
showCart: true
};
展开运算符 (...
) 执行“浅”合并。您的代码本质上正在做什么:
let addToCartState = shallowCopy(state);
addToCartState.items = { [action.id]: { /* ... */ } };
addToCartState.showCart = true;
换句话说,它“覆盖了前一项”,因为您将 items
属性替换为仅包含一项的新对象。一种解决方案是自己合并items
:
const addToCartState = { ...state,
items: { ...state.items,
[action.id]: { /* ... */ },
},
showCart: true,
};
...但是由于您使用的是 Immutable.js,所以您不应该这样做。您应该使用其内置的 mergeDeep
方法:
function addToCart(prevState, action) {
const addToCartState = {
items: {
[action.id]: {
color: action.product_selection.color,
// ...
},
},
showCart: true,
};
return prevState.mergeDeep(addToCartState);
}
let state = Immutable.fromJS({ items: {} });
console.log('Original state:', state);
console.log('Add blue thing');
state = addToCart(state, {
id: '123',
product_selection: { color: 'blue' },
});
console.log('State is now:', state);
console.log('Add green thing');
state = addToCart(state, {
id: '456',
product_selection: { color: 'green' },
});
console.log('State is now:', state);
.as-console-wrapper{min-height:100%}
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.min.js"></script>
Problem: This seems to work, but I can't seem to grab data from the state map. I can't seem to call "state.cart.items" (see mapStateToProps) like I can on my other states.
state
不是一个“普通”JavaScript 对象,它是一个 Immutable.Map。您无法像普通对象属性一样访问它的值。一种解决方案是使用 toJS
将其转换为普通对象,然后像往常一样检索其属性(和子属性)。如果您的状态对象可能很大,另一种选择是使用 Immutable.js 的 get
和 getIn
(对于“深层”属性)检索值。对于后者,如果它们也是不可变对象(immutable对象),则必须对各个值使用 toJS
。您可以在下面看到这两种方法。
function mapStateToProps(state) {
const obj = state.toJS();
return { products: obj.products, items: obj.cart.items };
}
// or...
function mapStateToPropsAlt(state) {
return {
products: state.get('products').toJS(),
items: state.getIn(['cart', 'items']).toJS(),
};
}
const state = Immutable.fromJS({
products: [ '¯\\_(ツ)_/¯' ],
cart: {
items: {
'123': { id: '123', color: 'blue', /* ... */ },
},
},
});
console.log('mapStateToProps(state) =>', mapStateToProps(state));
console.log('mapStateToPropsAlt(state) =>', mapStateToPropsAlt(state));
.as-console-wrapper{min-height:100%}
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.min.js"></script>
关于javascript - Redux 的问题 - 从状态添加和删除项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44185629/