状态中的对象正在更改而不会被提示

时间:2017-11-06 13:48:50

标签: reactjs

我使用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>
)
}

当检查反应开发者工具中我的项目对象的状态时,我看到每次单击按钮将项目添加到购物车时,它都会正确地将项目添加到购物车/更新项目的数量但是它还会更新我所在州的items对象中的项目,添加一个&#39; qty&#39;键/值对不是我想要的。

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

1 个答案:

答案 0 :(得分:2)

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

您的代码不是复制项目在线(var numbers = new List<Number> { new Number {X = 1, Y = 137}, new Number {X = 1, Y = 143}, new Number {X = 11, Y = 37}, new Number {X = 11, Y = 46}, new Number {X = 11, Y = 132}, new Number {X = 46, Y = 65}, new Number {X = 46, Y = 139}, new Number {X = 69, Y = 90} }; var result = numbers.GroupBy(c => c.X); var result2 = numbers.FirstOrDefault(c => result.Select(d => d.Key).Contains(c.Y)); var finalResult = numbers.Where(x => x.X == result2?.Y) .Select(x => { x.X = result2.X;x.Y = x.Y; return x; } ) .Union(numbers.Where(c => c.X != result2?.Y)).GroupBy(c => c.X , (key, element) => new { Key = key, Element = element.Select(c => c.Y).ToList() }); )。相反,它会从同一项目中添加引用,并且通过更改下一行中的newCart[key] = item;,您也会在qty键中更新它。

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