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

Кўриб турганingizдек, компонентларнинг пропсларига фақатгина маълумотлар эмас, балки функцияларни ҳам ўтказish мумкин.

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 компонентини олинг. Унда фойдаланувчини бан қилиш учун тугма ясанг.