Ändern des Parent-State in einer Child-Komponente in React

In der vorherigen Lektion wurde der State mit den Daten in der Parent-Komponente gespeichert, und die Child- Komponenten erhielten diese Daten als Props.

Nehmen wir nun an, wir möchten unsere Produkte ändern. Wir erstellen beispielsweise einen Button, der unser Produkt in den Warenkorb legt. Fügen wir zunächst unserem Produkt-Array ein Feld inCart hinzu, das anzeigt, ob sich das Produkt im Warenkorb befindet oder nicht:

jsxconst initProds = [
  {id: id(), name: 'product1', cost: 100, inCart: false},
  {id: id(), name: 'product2', cost: 200, inCart: false},
  {id: id(), name: 'product3', cost: 300, inCart: false},
];

In der Komponente Products fügen wir dem Produkt-Tag ein weiteres Attribut inCart hinzu:

jsxfunction Products() {
  const [prods, setProds] = useState(initProds);
  
  const items = prods.map(prod => {
    return <Product
      key   ={prod.id}
      name  ={prod.name}
      cost  ={prod.cost}
      inCart={prod.inCart}
    />;
  });
  
  return <div>
    {items}
  </div>;
}

Erstellen wir nun in der Child-Komponente Product eine Ausgabe der Warenkorb-Information und einen Button zum Hinzufügen zum Warenkorb:

jsxfunction Product({ id, name, cost, inCart }) {
  return <div>
    name: <span>{name}</span>,
    cost: <span>{cost}</span>,
    <span>{inCart ? 'in cart' : 'not in cart'}</span>
    <button>to cart</button>
  </div>;
}

Implementieren des Hinzufügens

Laut React-Regeln sollte eine Komponente nicht ihre eigenen Props ändern. Das bedeutet, dass die Child-Komponente sich nicht selbst in den Warenkorb legen kann, indem sie das Prop inCart ändert. Das ist nicht korrekt.

Korrekt wäre, die Parent-Komponente zu bitten, ihren State prods zu ändern und ein bestimmtes Produkt in den Warenkorb zu legen.

Sehen wir uns an, wie das gemacht wird.

Erstellen wir in der Parent-Komponente eine Funktion addToCart, die die id des Produkts als Parameter entgegennimmt und für dieses Produkt die Eigenschaft inCart auf true setzt:

jsxfunction addToCart(id) {
  setProds(prods.map(prod => {
    if (prod.id === id) {
      prod.inCart = true;
    }
    
    return prod;
  }));
}

Dem Produkt-Tag fügen wir ein Attribut hinzu, in dem wir die von uns erstellte Funktion übergeben, sowie ein weiteres Attribut, in dem wir die id des Produkts übergeben:

jsxconst items = prods.map(prod => {
  return <Product
    key      ={prod.id}
    id       ={prod.id}
    name     ={prod.name}
    cost     ={prod.cost}
    inCart   ={prod.inCart}
    addToCart={addToCart}
  />;
});

Wie Sie sehen, können an Komponenten-Props nicht nur Daten, sondern auch Funktionen übergeben werden.

Der endgültige Code der Products-Komponente wird wie folgt aussehen:

jsxfunction Products() {
  const [prods, setProds] = useState(initProds);
  
  function addToCart(id) {
    setProds(prods.map(prod => {
      if (prod.id === id) {
        prod.inCart = true;
      }
      
      return prod;
    }));
  }
  
  const items = prods.map(prod => {
    return <Product
      key      ={prod.id}
      id       ={prod.id}
      name     ={prod.name}
      cost     ={prod.cost}
      inCart   ={prod.inCart}
      addToCart={addToCart}
    />;
  });
  
  return <div>
    {items}
  </div>;
}

Nun ist in der Child-Komponente die Funktion addToCart verfügbar. Rufen wir diese Funktion beim Klick auf den Button auf und übergeben ihr die id des Produkts als Parameter:

jsxfunction Product({ id, name, cost, inCart, addToCart }) {
  return <div>
    name: <span>{name}</span>,
    cost: <span>{cost}</span>,
    <span>{inCart ? 'in cart' : 'not in cart'}</span>
    <button onClick={() => addToCart(id)}>to cart</button>
  </div>;
}

Das Ergebnis ist, dass beim Klick auf den Button im Child die Funktion des Parents aufgerufen wird, die dann den Parent-State ändert. Die Änderung des Parent-State wird ein Re-Rendering auslösen und unser Produkt neu zeichnen, wobei ihm der geänderte Prop übergeben wird.

Задание 1

Nehmen Sie die User-Komponente aus der vorherigen Lektion. Sorgen Sie dafür, dass darin ein Button zum Bannen eines Users erscheint.