Kódím.cz
6

State lifting

Naučíme se techniku přesouvání stavu nahoru ve stromě komponent

State lifting

Sdílení dat a komunikace mezi komponentami je jedna z největších výzev v architektuře Reactových aplikací. V praxi budeme často v situaci, kdy nějaká komponenta potřeboje data zevnitř některého ze svých potomků. React však nemá žádný nástroj nebo příkaz, jakým by předek mohl z potomka získat data. Tuto situaci musíme vyřešit pomocí techniky s názvem state liftingpovýšení stavu.

Ukázka: Hračkorama

K ilustraci výše popsané situace použijeme project e-shopu Hračkorama. Základ projektu najdete v tomto repozitáři.

V tuto chvíli nás bude zajímat komponenta Amount. Ta umožňuje zvolit počet kusů daného produktu. V komponentě Cart budeme chtít zobrazovat celkový počet položek v košíku. Bohužel tato komponenta se nemá jak dostat k číslu ve stavu komponenty Amount. Budeme tedy muset provést povýšení stavu.

Nejprve z cvičných důvodů povýšíme stav do kompnenty CartItem. To sice náš problém ještě nevyřeší, ale ukázeme si tím základní principy.

Stav count nyní bude v komponentě CartItem.

interface ICartItemProps {
  product: IProduct;
}

const CartItem: React.FC<ICartItemProps> = ({ product }) => {
  return (
    <div className="cart-item">
      <CartProduct name={product.name} price={product.price} />
      <Amount value={product.amount} />
    </div>
  )
};

Stav pak předáme pomocí prop value do komponenty Amount. Nyní potřebujeme, aby komponenta Amount dala vědět o změně své hodnoty.

const CartItem: React.FC<ICartItemProps> = ({ product }) => {
  const [count, setCount] = useState<number>(product.amount);

  const handleAmountChange = (newCount) => {
    setCount(newCount);
  }

  return (
    <div className="cart-item">
      <CartProduct name={product.name} price={product.price} />
      <Amount value={count} onChange={handleAmountChange} />
    </div>
  )
};

Komponenta Amount pak bude vypadat takto:

interface IAmountProps {
  value: number;
  onChange: (newCount: number) => void;
}

const Amount: React.FC<IAmountProps> = ({ value, onChange }) => {
  const handelIncrement = () => {
    onChange(value + 1);
  }

  const handelDecrement = () => {
    if (count > 0) {
      onChange(value - 1);
    }
  }

  return (
    <div className="amount">
      <button className="amount__btn" onClick={handelDecrement}></button>
      <div className="amount__count">{value}</div>
      <button className="amount__btn" onClick={handelIncrement}>+</button>
    </div>
  );
};

Chování aplikace se tímto nezměnilo, stav jsme však povýšili o jednu úroveň výše.