【问题标题】:Object within state is changing without being prompted状态中的对象在没有提示的情况下发生变化
【发布时间】:2017-11-06 13:48:49
【问题描述】:

我正在使用 setState 来更新特定对象,但由于某种原因,即使我没有在 setState 函数中添加另一个对象,它也会发生变异。

基本上我有一个“添加到购物车”功能,如果购物车状态对象中已经存在商品,只需将其数量增加 1。如果没有,使用包含所述商品的副本更新购物车状态。

this.state = {
  items: {
    0: { name: 'Red shirt', price: 10 },
    1: { name: 'Blue shirt', price: 11 },
    2: { name: 'Green shirt', price: 12 },
    3: { name: 'Yellow shirt', price: 13 }
  },
  cart: {},
  user: {}
}

addToCart = (key, item) => {
 let newCart;
 newCart = this.state.cart;

 // item already exists in cart
 if (newCart[key]) {
  // increment qty of added item
  newCart[key].qty++;
  // does not exist, need to add to cart
 } else {
  newCart[key] = item;
  newCart[key].qty = 1;
 }
 this.setState({ cart: newCart });
}

  render() {
const { cart, items } = this.state;
return (
  <div className="App">
    <h1>Streat</h1>
    <Checkout cart={cart} />
    <Items
      items={items}
      addToCart={this.addToCart}
    />
  </div>
);
}
}

// Items component which holds Item component
class Items extends Component {
constructor(props) {
    super(props)
}

render() {
    const { items, addToCart } = this.props;
    return (
        <div>
            {
                map(items, function renderItems(item, key) {
                    return <Item
                        item={item}
                        itemRef={key}
                        key={key}
                        addToCart={addToCart} />
                })
            }
        </div>
    )
}
}

// Item functional component which has the add to cart button
const Item = (props) => {
const { item, itemRef, addToCart } = props;
return (
    <div>
        <p>{item.name}</p>
        <p>{item.price}</p>
        <p>{item.qty || ""}</p>
        <button onClick={() => addToCart(itemRef, item)}>Add</button>
    </div>
)
}

在 react 开发人员工具中检查我的 items 对象的状态时,我看到每次单击按钮将商品添加到购物车时,它都会正确地将商品添加到购物车/更新商品的数量,但是它还会在我的状态下更新项目对象中的项目,添加一个“数量”键/值对,这不是我想要的。

我在我的购物车对象上使用了 setState,但我的 items 对象也因某种原因被更改了。

【问题讨论】:

  • 你能加你总码吗
  • @Geeky 完成 :)!

标签: reactjs


【解决方案1】:

尝试使用spread syntax 更新您的状态,这样您就不会遇到这种麻烦。 Redux 也经常使用它。通过这样做,您不会改变您的对象并创建它们的干净副本。

您的代码没有复制在线项目 (newCart[key] = item;)。相反,它是从同一个项目中引用,并通过更改下一行中的qty,从而在items 键中更新它。

const Item = ({ name, price, onClick }) =>
  <div onClick={onClick}>
    {name} {price}
  </div>

class App extends React.Component {
  constructor() {
    super()

    this.state = {
      items: {
        0: { name: 'Red shirt', price: 10 },
        1: { name: 'Blue shirt', price: 11 },
        2: { name: 'Green shirt', price: 12 },
        3: { name: 'Yellow shirt', price: 13 }
      },
      cart: {},
      user: {}
    }
  }
  
  addToCart(key, item) {
    const hasItem = this.state.cart[key]
    
    this.setState({
      ...this.state,
      cart: {
        ...this.state.cart,
        [key]: {
          ...(hasItem ? this.state.cart[key] : item),
          qty: hasItem ? this.state.cart[key].qty + 1 : 1,
        },
      },
    })
  }

  render() {
    const { cart, items } = this.state
     
    return (
      <div>
        <div>Click to add:</div>
        {Object.keys(items).map(key =>
          <Item
            {...items[key]}
            key={key}
            onClick={this.addToCart.bind(this, key, items[key])}
          />
        )}
        
        <div style={{ marginTop: 20 }}>
          {Object.keys(cart).map(key =>
            <div key={key}>{cart[key].name}:{cart[key].qty}</div>
          )}
        </div>
      </div>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root"></div>

【讨论】:

  • 不确定该块是否是一个合法的解决方案(没有工作)或只是一个建议。我会尝试研究一下传播语法的方式,看看它是否有什么不同。
  • @jonathanpuc 是的,这是一个解决方案。检查我的工作样本:)
  • 哇,它有效,谢谢。我不太明白这里发生了什么: [key]: { ...(hasItem ? this.state.cart[key] : item), qty: hasItem ? this.state.cart[key].qty + 1 : 1, } 我不明白第二行如何使用扩展运算符。你能解释一下吗? :)
  • 当然。由于cart 是一个对象,key 负责处理应该更新cart 中的哪个属性。如果hasItemtrue,则将现有项目传播到key.. 否则传播来自参数的项目,以便在cart 中创建一个新条目。同样的逻辑也适用于在该项目上设置qty
猜你喜欢
  • 2019-01-22
  • 2022-01-25
  • 2019-12-15
  • 1970-01-01
  • 2020-01-27
  • 2015-08-10
  • 1970-01-01
  • 1970-01-01
  • 2018-09-26
相关资源
最近更新 更多