2017-11-06 1 views
0

Ich verwende SetState, um ein bestimmtes Objekt zu aktualisieren, aber aus irgendeinem Grund wird ein anderes Objekt ebenfalls mutiert, obwohl ich es nicht in der Funktion setState hinzugefügt habe.Objekt in Zustand ändert sich, ohne aufgefordert zu werden

Grundsätzlich habe ich eine "in den Warenkorb" -Funktion, wenn Artikel bereits im Warenkorb Statusobjekt existiert, wird nur die Menge um 1 inkrementiert. Wenn nicht, Status des Wagens mit einer Kopie aktualisieren, die das Element enthält.

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

Wenn der Zustand meiner Artikel Prüfobjekt reagieren in Entwickler-Tools, wie ich sehe, dass jedes Mal, wenn ich auf die Schaltfläche klicken ein Element in den Warenkorb zu legen, ist es richtig, die Artikel in den Warenkorb gelegt fügt/aktualisieren, um die Menge der Artikel, aber es aktualisiert auch das Element in den Objekten in meinem Zustand, Hinzufügen eines 'Menge' Schlüssel/Wert-Paar, das ist nicht was ich will.

Ich benutze SetState auf meinem Warenkorb-Objekt, aber meine Objekte Objekt wird auch aus irgendeinem Grund geändert.

+0

können Sie fügen Sie Code – Geeky

+0

@Geeky insgesamt getan :)! – jonathanpuc

Antwort

2

Versuchen Sie, Ihren Zustand zu aktualisieren, indem Sie spread syntax verwenden, damit Sie nicht in diese Art von Schwierigkeiten geraten. Redux verwendet auch das sehr. Indem Sie dies tun, mutieren Sie Ihr Objekt nicht und erstellen eine saubere Kopie von ihnen.

Ihr Code ist nicht Kopieren das Element on line (newCart[key] = item;). Stattdessen wird eine Referenz vom selben Objekt eingegeben und durch die Änderung der qty in der nächsten Zeile wird diese ebenso aktualisiert wie im Schlüssel 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>

+0

Nicht sicher, ob dieser Block eine legitime Lösung sein sollte (nicht funktioniert) oder nur ein Vorschlag war. Ich werde versuchen, den Spread-Syntax-Weg zu untersuchen und zu sehen, ob es einen Unterschied macht. – jonathanpuc

+0

@jonathanpuc Ja, es ist eine Lösung. Überprüfen Sie mein Arbeitsprobe :) – mersocarlin

+0

Wooh es funktioniert, danke. Ich verstehe nicht ganz, was los ist hier aber: [key]: { ... (hasItem this.state.cart [key]: Artikel), Menge: hasItem? this.state.cart [key] .qty + 1: 1, } Ich verstehe nicht, wie der Spread-Operator in der 2. Zeile verwendet wird. Könnten Sie bitte erklären? :) – jonathanpuc

Verwandte Themen