Redigering av föräldratillstånd i en barnkomponent i React

Låt oss nu redigera våra produkter med hjälp av inmatningsfält. För att göra detta, skapa en knapp i barnkomponenten.

Vid första klicket på denna knapp, låt oss istället för namn och pris på produkten visa inmatningsfält för att redigera dem, och vid andra klicket visa texterna igen istället för inmatningsfälten.

Låt oss ändra arrayen med produkter genom att lägga till egenskapen isEdit (och ta bort kundvagnsfunktionen för enkelhetens skull):

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

Komponenten Product

Låt oss skapa en knapp för redigering i produkten:

jsxfunction Product({ id, name, cost, isEdit }) {
  return <div>
    name: <span>{name}</span>
    cost: <span>{cost}</span>
    <button>edit</button>
  </div>;
}

Låt oss göra så att när man klickar på denna knapp anropas en funktion toggleMode, som skickats från förälderkomponenten:

jsxfunction Product({ id, name, cost, isEdit, toggleMode }) {
  return <div>
    name: <span>{name}</span>
    cost: <span>{cost}</span>
    
    <button onClick={() => toggleMode(id)}>
      edit
    </button>
  </div>;
}

Vi har ännu ingen implementation av toggleMode, men vi vet att den kommer att finnas i förälderkomponenten, ta id för produkten som parameter och ändra egenskapen isEdit för produkten till motsatt värde.

Låt oss också göra så att knappens text ändras vid varje klick:

jsxfunction Product({ id, name, cost, isEdit, toggleMode }) {
  return <div>
    name: <span>{name}</span>
    cost: <span>{cost}</span>
    
    <button onClick={() => toggleMode(id)}>
      {isEdit ? 'save': 'edit'}
    </button>
  </div>;
}

Låt oss nu göra så att i redigeringsläget visas inmatningsfält med data, och i normalt läge - spann-element:

jsxfunction Product({ id, name, cost, isEdit, toggleMode }) {
  return <div>
    name: {isEdit ? <input value={name} /> : <span>{name}</span>}
    cost: {isEdit ? <input value={cost} /> : <span>{cost}</span>}
    
    <button onClick={() => toggleMode(id)}>
      {isEdit ? 'save': 'edit'}
    </button>
  </div>;
}

Låt oss koppla onChange-händelsen till våra inmatningsfält, där vi kommer att anropa en förälderfunktion editProd:

jsxfunction Product({ id, name, cost, isEdit, toggleMode, editProd }) {
  return <div>
    name: {
      isEdit
      ? <input value={name} onChange={event => editProd(id, 'name', event)} />
      : <span>{ name }</span>
    }
    cost: {
      isEdit
      ? <input value={cost} onChange={event => editProd(id, 'cost', event)} />
      : <span>{ cost }</span>
    }
    
    <button onClick={() => toggleMode(id)}>
      {isEdit ? 'save': 'edit'}
    </button>
  </div>;
}

Komponenten Products

Låt oss nu gå till komponenten Products. Låt oss implementera funktionen toggleMode i den:

jsxfunction toggleMode(id) {
  setProds(prods.map(prod => {
    if (prod.id === id) {
      prod.isEdit = !prod.isEdit;
    }
    
    return prod;
  }));
}

Låt oss också implementera funktionen editProd i den:

jsxfunction editProd(id, field, event) {
  setProds(prods.map(prod => {
    if (prod.id === id) {
      prod[field] = event.target.value;
    }
    
    return prod;
  }));
}

Låt oss skicka våra funktioner toggleMode och editProd som attribut till produkt-taggen:

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

Den slutgiltiga koden för komponenten Products kommer att se ut så här:

jsxfunction Products() {
  const [prods, setProds] = useState(initProds);
  
  function toggleMode(id) {
    setProds(prods.map(prod => {
      if (prod.id === id) {
        prod.isEdit = !prod.isEdit;
      }
      
      return prod;
    }));
  }
  
  function editProd(id, field, event) {
    setProds(prods.map(prod => {
      if (prod.id === id) {
        prod[field] = event.target.value;
      }
      
      return prod;
    }));
  }
  
  const result = prods.map(prod => {
    return <Product
      key ={prod.id}
      id  ={prod.id}
      name={prod.name}
      cost={prod.cost}
      isEdit={prod.isEdit}
      toggleMode={toggleMode}
      editProd={editProd}
    />;
  });
  
  return <div>
    {result}
  </div>;
}

Praktiska uppgifter

Задание 1

Utför liknande operationer med komponenterna Users och User, som du skapade i tidigare lektioner.