我正在购买购物车,我正试着用我的应用程序解决两个问题:
向商店添加商品会覆盖商店中的先前商品:
初始状态:
const initialState = {
items: {},
showCart: false
};
添加到购物车减速机:
问题:这适用于将商品添加到购物车,但当我在购物车中添加其他商品时,它会覆盖之前的商品。为什么会这样/我如何保留以前状态的项目?
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);
全部从购物车减速器中删除:
问题:这似乎有效,但我似乎无法从州地图中获取数据。我似乎无法在其他州调用“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 }
}
state.cart:
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
});
答案 0 :(得分:3)
问题的根源在于您将常规JavaScript对象视为Immutable.js对象,而不是使用内置的Immutable.js功能来执行您正在执行的任务。
问题:这适用于将商品添加到购物车,但当我在购物车中添加其他商品时,它会覆盖上一个商品。为什么会这样/我如何保留以前状态的项目?
让我们来看看您的代码:
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>
&#13;
问题:这似乎有效,但我似乎无法从状态图中获取数据。我似乎无法打电话给#34; state.cart.items&#34; (见mapStateToProps)就像我可以在其他州一样。
state
不是&#34;普通&#34; JavaScript对象,它是一个Immutable.Map。您无法像普通对象属性那样访问其值。一种解决方案是使用toJS
将其转换为普通对象,然后像往常一样检索其属性(和子属性)。如果您的状态对象可能很大,那么另一种选择是使用Immutable.js&#39;来检索值。 get
和getIn
(&#34;深&#34;属性)。对于后者,如果它们也是不可变对象,则必须对单个值使用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));
&#13;
.as-console-wrapper{min-height:100%}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.min.js"></script>
&#13;