javascript - Redux 的问题 - 从状态添加和删除项目

标签 javascript ecmascript-6 redux immutable.js

我正在开发一个购物车,并且正在尝试解决应用程序中的两个问题:

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

初始状态:

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 的 getgetIn (对于“深层”属性)检索值。对于后者,如果它们也是不可变对象(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/

相关文章:

javascript - PHP 是单独存储 session 还是共享内存?

javascript - iOS JavaScript 支持 timedMetadata

javascript - 如何修复从 api 传入的数据以在表格中正确显示?

typescript - 如何在 TypeScript 3 中正确使用 fromCharCode.apply 和 Uint8Array?

javascript - 为什么可以改变我的状态的浅拷贝?

javascript - 将单个数据字符串从操作传递到组件 React/Redux/ES6 的最佳方式

javascript - Redux - 从状态中删除项目

javascript - document.write 样式 css javascript

javascript - 使用计算属性名称创建内部对象

javascript - 在 React 中如何根据对象值勾选输入复选框