Ата-ана күйін бала компонентте өзгерту React-те

Алдыңғы сабақта бізде деректер күйі ата-ана компонентте сақталды, ал бала компоненттер бұл деректерді пропс ретінде алатын.

Енді біз өнімдерімізді өзгерткіміз келеді делік. Мысалы, біздің өнімімізді себетке салатын батырманы жасайық. Алдымен өнімдеріміздің массивіне inCart өрісін қосамыз, бұл өнім себетте ме жоқ па екенін көрсетеді:

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},
];

Products компонентінде өнім бар тегке тағы бір inCart атрибутын қосамыз:

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

Product бала компонентінде себет туралы ақпаратты шығаруды және себетке қосу үшін батырманы жасайық:

jsxfunction Product({ id, name, cost, inCart }) {
  return <div>
    аты: <span>{name}</span>,
    бағасы: <span>{cost}</span>,
    <span>{inCart ? 'себетте' : 'себетте жоқ'}</span>
    <button>себетке</button>
  </div>;
}

Қосуды жүзеге асырамыз

React ережелері бойынша компонент өз пропстарын өзгертуге болмайды. Бұл бала компоненттің өзін-өзі себетке сала алмайтынын білдіреді, inCart пропсын өзгерту арқылы. Бұл дұрыс емес.

Ата-ана компоненттен өз prods күйін өзгертуді сұрау, белгілі бір өнімді себетке салу дұрыс болады.

Мұны қалай жасайтынын қарап көрейік.

Ата-ана компонентте addToCart функциясын жасаймыз, ол параметр ретінде өнімнің id-сін қабылдайды және осы өнім үшін inCart қасиетін true-ге өзгертеді:

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

Өнім бар тегке біз жасаған функцияны беретін атрибутты қосамыз, сонымен қатар өнімнің id-сін беретін атрибутты қосамыз:

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

Көріп отырғаныңыздай, компонент пропстарына тек қандай да бір деректерді ғана емес, функцияларды да бере аласыз.

Products класының соңғы коды келесідей болады:

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

Енді бала класында бізде addToCart функциясы қолжетімді болады. Баттырманы басқанда осы функцияны шаламыз, оған өнімнің id-сін параметр ретінде беріп:

jsxfunction Product({ id, name, cost, inCart, addToCart }) {
  return <div>
    аты: <span>{name}</span>,
    бағасы: <span>{cost}</span>,
    <span>{inCart ? 'себетте' : 'себетте жоқ'}</span>
    <button onClick={() => addToCart(id)}>себетке</button>
  </div>;
}

Баладағы батырманы басқанда ата-ананың функциясы шақырылады, ол ата-ана күйін өзгертеді. Ата-ана күйінің өзгеруі қайтарендерингті тудырып, біздің өнімімізді өзгертілген пропсты беріп қайта сызады.

Задание 1

Алдыңғы сабақтан User компонентін алыңыз. Онда пайдаланушыны банға алу үшін батырманы жасаңыз.