Redux的问题 - 添加&从状态中删除项目

时间:2017-05-25 16:38:46

标签: javascript ecmascript-6 redux immutable.js

我正在购买购物车,我正试着用我的应用程序解决两个问题:

向商店添加商品会覆盖商店中的先前商品:

初始状态:

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

1 个答案:

答案 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;
&#13;
&#13;

  

问题:这似乎有效,但我似乎无法从状态图中获取数据。我似乎无法打电话给#34; state.cart.items&#34; (见mapStateToProps)就像我可以在其他州一样。

state不是&#34;普通&#34; JavaScript对象,它是一个Immutable.Map。您无法像普通对象属性那样访问其值。一种解决方案是使用toJS将其转换为普通对象,然后像往常一样检索其属性(和子属性)。如果您的状态对象可能很大,那么另一种选择是使用Immutable.js&#39;来检索值。 getgetIn(&#34;深&#34;属性)。对于后者,如果它们也是不可变对象,则必须对单个值使用toJS。你可以在下面看到这两种方法。

&#13;
&#13;
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;
&#13;
&#13;