Skip to content

Latest commit

 

History

History
800 lines (666 loc) · 25.4 KB

File metadata and controls

800 lines (666 loc) · 25.4 KB
title Dodawanie interaktywności

Niektóre elementy na ekranie aktualizują się w odpowiedzi na interakcje użytkownika. Na przykład kliknięcie w galerię obrazów zmienia aktywny obraz. W Reakcie dane, które zmieniają się w czasie, nazywane są stanem (ang. state). Możesz dodać stan do każdego komponentu i aktualizować go w razie potrzeby. W tym rozdziale nauczysz się, jak pisać komponenty obsługujące interakcje, aktualizujące swój stan i wyświetlające różne wyniki w czasie.

Reagowanie na zdarzenia {/responding-to-events/}

React pozwala na dodawanie procedur obsługi zdarzeń (ang. event handlers) do twojej składni JSX. Procedury obsługi zdarzeń to twoje własne funkcje, które zostaną wywołane w odpowiedzi na interakcje użytkownika, takie jak kliknięcia, najechanie kursorem, skupienie na elementach formularza i inne.

Wbudowane komponenty, takie jak <button>, obsługują jedynie wbudowane zdarzenia przeglądarki, takie jak onClick. Jednakże możesz też tworzyć własne komponenty i nadawać ich właściwościom obsługującym zdarzenia dowolne nazwy specyficzne dla twojej aplikacji.

export default function App() {
  return (
    <Toolbar
      onPlayMovie={() => alert('Odtwarzanie!')}
      onUploadImage={() => alert('Wgrywanie!')}
    />
  );
}

function Toolbar({ onPlayMovie, onUploadImage }) {
  return (
    <div>
      <Button onClick={onPlayMovie}>
        Odtwórz film
      </Button>
      <Button onClick={onUploadImage}>
        Wgraj obraz
      </Button>
    </div>
  );
}

function Button({ onClick, children }) {
  return (
    <button onClick={onClick}>
      {children}
    </button>
  );
}
button { margin-right: 10px; }

Przeczytaj rozdział Reagowanie na zdarzenia, aby dowiedzieć się, jak dodawać procedury obsługi zdarzeń.

Stan - pamięć komponentu {/state-a-components-memory/}

Komponenty często muszą zmieniać to, co jest wyświetlane na ekranie w wyniku interakcji. Wpisywanie w formularzu powinno aktualizować jego pole, kliknięcie "następny" w kolejce obrazów powinno zmieniać wyświetlany obraz, kliknięcie "kup" powinno umieścić produkt w koszyku. Komponenty muszą "pamiętać" różne rzeczy: bieżącą wartość pola, bieżący obraz, zawartość koszyka. W Reakcie tego rodzaju pamięć specyficzna dla komponentu nazywana jest stanem.

Możesz dodać stan do komponentu za pomocą hooka useState. Hooki to specjalne funkcje, które pozwalają twoim komponentom korzystać z funkcjonalności Reacta (stan jest jedną z tych funkcjonalności). Hook useState pozwala zadeklarować zmienną stanu. Przyjmuje on stan początkowy i zwraca parę wartości: bieżący stan oraz funkcję ustawiającą stan, która pozwala na jego aktualizację.

const [index, setIndex] = useState(0);
const [showMore, setShowMore] = useState(false);

Oto jak galeria obrazów wykorzystuje i aktualizuje stan po kliknięciu:

import { useState } from 'react';
import { sculptureList } from './data.js';

export default function Gallery() {
  const [index, setIndex] = useState(0);
  const [showMore, setShowMore] = useState(false);
  const hasNext = index < sculptureList.length - 1;

  function handleNextClick() {
    if (hasNext) {
      setIndex(index + 1);
    } else {
      setIndex(0);
    }
  }

  function handleMoreClick() {
    setShowMore(!showMore);
  }

  let sculpture = sculptureList[index];
  return (
    <>
      <button onClick={handleNextClick}>
        Następny
      </button>
      <h2>
        <i>{sculpture.name} </i>
        autorstwa {sculpture.artist}
      </h2>
      <h3>
        ({index + 1} of {sculptureList.length})
      </h3>
      <button onClick={handleMoreClick}>
        {showMore ? 'Ukryj' : 'Pokaż'} detale
      </button>
      {showMore && <p>{sculpture.description}</p>}
      <img
        src={sculpture.url}
        alt={sculpture.alt}
      />
    </>
  );
}
export const sculptureList = [{
  name: 'Homenaje a la Neurocirugía',
  artist: 'Marta Colvin Andrade',
  description: 'Chociaż Colvin jest głównie znana z abstrakcyjnych tematów nawiązujących do symboli prekolumbijskich, ta gigantyczna rzeźba, hołd dla neurochirurgii, jest jednym z jej najbardziej rozpoznawalnych dzieł sztuki publicznej.',
  url: 'https://i.imgur.com/Mx7dA2Y.jpg',
  alt: 'Brązowy posąg dwóch skrzyżowanych rąk delikatnie trzymających ludzki mózg w opuszkach palców.'
}, {
  name: 'Floralis Genérica',
  artist: 'Eduardo Catalano',
  description: 'Ten ogromny (75 stóp lub 23 m) srebrny kwiat znajduje się w Buenos Aires. Jest zaprojektowany w taki sposób, aby się poruszać, zamykając swoje płatki wieczorem lub podczas silnych wiatrów, a otwierając je rano.',
  url: 'https://i.imgur.com/ZF6s192m.jpg',
  alt: 'Gigantyczna metalowa rzeźba kwiatu z refleksyjnymi płatkami przypominającymi lustro i mocnymi pręcikami.'
}, {
  name: 'Eternal Presence',
  artist: 'John Woodrow Wilson',
  description: 'Wilson był znany ze swojego zainteresowania równością, sprawiedliwością społeczną, a także istotnymi i duchownymi cechami ludzkości. Ta ogromna (7 stóp lub 2,13 m) rzeźba z brązu przedstawia to, co opisał jako "symboliczną czarną obecność nasyconą poczuciem uniwersalnej ludzkości".',
  url: 'https://i.imgur.com/aTtVpES.jpg',
  alt: 'Rzeźba przedstawiająca ludzką głowę wydaje się być zawsze obecna i poważna. Promieniuje spokojem i harmonią.'
}, {
  name: 'Moai',
  artist: 'nieznanego',
  description: 'Na Wyspie Wielkanocnej znajduje się 1000 moai, czyli monumentalnych posągów stworzonych przez wczesnych ludzi Rapa Nui, które niektórzy uważają za przedstawienia deifikowanych przodków.',
  url: 'https://i.imgur.com/RCwLEoQm.jpg',
  alt: 'Trzy monumentalne kamienne popiersia z głowami, które są nieproporcjonalnie duże, o smutnych twarzach.'
}, {
  name: 'Blue Nana',
  artist: 'Niki de Saint Phalle',
  description: 'Nany to tryumfujące stworzenia, symbole kobiecości i macierzyństwa. Początkowo, Saint Phalle używała tkanin i znalezionych przedmiotów do tworzenia Nan, a później wprowadziła poliester, aby uzyskać bardziej żywy efekt.',
  url: 'https://i.imgur.com/Sd1AgUOm.jpg',
  alt: 'Duża mozaikowa rzeźba cudacznej, tańczącej kobiecej figury w kolorowym kostiumie, emanująca radością.'
}, {
  name: 'Ultimate Form',
  artist: 'Barbara Hepworth',
  description: 'Ta abstrakcyjna rzeźba z brązu jest częścią serii "The Family of Man" znajdującej się w Yorkshire Sculpture Park. Hepworth zdecydowała się nie tworzyć dosłownych reprezentacji świata, lecz opracowała abstrakcyjne formy inspirowane ludźmi i krajobrazami.',
  url: 'https://i.imgur.com/2heNQDcm.jpg',
  alt: 'Wysoka rzeźba składająca się z trzech elementów ułożonych jeden na drugim, przypominająca ludzką postać.'
}, {
  name: 'Cavaliere',
  artist: 'Lamidi Olonade Fakeye',
  description: 'Pochodzący z rodziny czterech pokoleń rzeźbiarzy w drewnie, prace Fakeye’a łączyły tradycyjne i współczesne motywy yoruba.',
  url: 'https://i.imgur.com/wIdGuZwm.png',
  alt: 'Skrupulatna rzeźba w drewnie przedstawiająca wojownika z skoncentrowaną twarzą na koniu ozdobionym wzorami.'
}, {
  name: 'Big Bellies',
  artist: 'Alina Szapocznikow',
  description: 'Szapocznikow jest znana ze swoich rzeźb przedstawiających fragmenty ciała jako metaforę kruchości i nietrwałości młodości oraz piękna. Ta rzeźba przedstawia dwa bardzo realistyczne, duże brzuchy ułożone jeden na drugim, każdy o wysokości około pięciu stóp (1,5 m).',
  url: 'https://i.imgur.com/AlHTAdDm.jpg',
  alt: 'Rzeźba przypomina kaskadę fałd, znacznie różniącą się od brzuchów w klasycznych rzeźbach.'
}, {
  name: 'Terakotowa Armia',
  artist: 'nieznanego',
  description: 'Terakotowa Armia to zbiór rzeźb z terakoty przedstawiających armię Qin Shi Huanga, pierwszego cesarza Chin. Armia składała się z ponad 8 000 żołnierzy, 130 wozów z 520 końmi oraz 150 koni kawaleryjskich.',
  url: 'https://i.imgur.com/HMFmH6m.jpg',
  alt: '12 rzeźb z terakoty przedstawiających poważnych wojowników, każdy z unikalnym wyrazem twarzy i zbroją.'
}, {
  name: 'Lunar Landscape',
  artist: 'Louise Nevelson',
  description: 'Nevelson była znana z pozyskiwania przedmiotów z odpadów Nowego Jorku, które później łączyła w monumentalne konstrukcje. W tej pracy wykorzystała różne części, takie jak noga łóżka, kij do żonglowania i fragment siedzenia, przybijając i klejąc je do pudełek, które odzwierciedlają wpływ geometrycznej abstrakcji kubizmu.',
  url: 'https://i.imgur.com/rN7hY6om.jpg',
  alt: 'Czarna matowa rzeźba, gdzie poszczególne elementy są początkowo nie do rozróżnienia.'
}, {
  name: 'Aureola',
  artist: 'Ranjani Shettar',
  description: 'Shettar łączy tradycję z nowoczesnością, naturę z przemysłem. Jej sztuka koncentruje się na relacji między człowiekiem a naturą. Jej prace opisywane są jako porywające zarówno w sensie abstrakcyjnym, jak i figuratywnym, nieważkie i jako „doskonała synteza nieoczywistych materiałów”.',
  url: 'https://i.imgur.com/okTpbHhm.jpg',
  alt: 'Jasna rzeźba przypominająca drut, zamocowana na betonowej ścianie i opadająca na podłogę. Wydaje się lekka.'
}, {
  name: 'Hippos',
  artist: 'Ogród Zoologiczny w Taipei',
  description: 'Ogród Zoologiczny w Taipei zlecił stworzenie Placu Hipopotamów z zanurzoną w wodzie grupą bawiących się hipopotamów.',
  url: 'https://i.imgur.com/6o5Vuyu.jpg',
  alt: 'Grupa rzeźb z brązu przedstawiająca hipopotamy wychodzące z chodnika, jakby pływały.'
}];
h2 { margin-top: 10px; margin-bottom: 0; }
h3 {
 margin-top: 5px;
 font-weight: normal;
 font-size: 100%;
}
img { width: 120px; height: 120px; }
button {
  display: block;
  margin-top: 10px;
  margin-bottom: 10px;
}

Przeczytaj rozdział Stan - Pamięć komponentu, aby dowiedzieć się, jak zapamiętywać wartość i aktualizować ją podczas interakcji.

Renderowanie i aktualizowanie {/render-and-commit/}

Zanim twoje komponenty zostaną wyświetlone na ekranie, muszą zostać wyrenderowane przez Reacta. Zrozumienie kroków w tym procesie pomoże ci zrozumieć, jak wykonuje się twój kod i wyjaśnić jego działanie.

Wyobraź sobie, że twoje komponenty to kucharze w kuchni, którzy przygotowują smaczne dania z dostępnych składników. W tej sytuacji React jest kelnerem, który przyjmuje zamówienia od klientów i przynosi im zamówione potrawy. Ten proces zgłaszania i obsługi interfejsu użytkownika składa się z trzech kroków:

  1. Wywołanie (ang. triggering) renderowania (przekazanie zamówienia od gościa do kuchni)
  2. Renderowanie (ang. rendering) komponentu (przygotowanie zamówienia w kuchni)
  3. Aktualizowanie (ang. committing) drzewa DOM (umieszczenie zamówienia na stole)

Przeczytaj rozdział Renderowanie i aktualizowanie, aby dowiedzieć się o cyklu życia aktualizacji interfejsu użytkownika.

Stan jako migawka {/state-as-a-snapshot/}

W przeciwieństwie do zwykłych zmiennych javascriptowych, stan w Reakcie zachowuje się bardziej jak migawka. Ustawienie stanu nie zmienia już istniejącej zmiennej stanu, lecz wywołuje przerenderowanie. Może to być na początki zaskakujące!

console.log(count);  // 0
setCount(count + 1); // Żądanie ponownego renderowania z wartością 1
console.log(count);  // Nadal 0!

To zachowanie pomaga unikać subtelnych błędów. Oto mała aplikacja do czatu. Spróbuj zgadnąć, co się stanie, jeśli najpierw naciśniesz "Wyślij", a potem zmienisz odbiorcę na Boba. Czyje imię pojawi się w alert pięć sekund później?

import { useState } from 'react';

export default function Form() {
  const [to, setTo] = useState('Alice');
  const [message, setMessage] = useState('Cześć');

  function handleSubmit(e) {
    e.preventDefault();
    setTimeout(() => {
      alert(`Wysłano wiadomość "${message}" do użytkownika ${to}`);
    }, 5000);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        To:{' '}
        <select
          value={to}
          onChange={e => setTo(e.target.value)}>
          <option value="Alice">Alice</option>
          <option value="Bob">Bob</option>
        </select>
      </label>
      <textarea
        placeholder="Message"
        value={message}
        onChange={e => setMessage(e.target.value)}
      />
      <button type="submit">Wyślij</button>
    </form>
  );
}
label, textarea { margin-bottom: 10px; display: block; }

Przeczytaj rozdział Stan jako migawka, aby dowiedzieć się, dlaczego stan wydaje się być "ustalony" i niezmienny wewnątrz funkcji obsługujących zdarzenia.

Kolejkowanie serii aktualizacji stanu {/queueing-a-series-of-state-updates/}

Ten komponent zawiera błąd: kliknięcie "+3" zwiększa wynik tylko raz.

import { useState } from 'react';

export default function Counter() {
  const [score, setScore] = useState(0);

  function increment() {
    setScore(score + 1);
  }

  return (
    <>
      <button onClick={() => increment()}>+1</button>
      <button onClick={() => {
        increment();
        increment();
        increment();
      }}>+3</button>
      <h1>Wynik: {score}</h1>
    </>
  )
}
button { display: inline-block; margin: 10px; font-size: 20px; }

Stan jako migawka wyjaśnia, dlaczego tak się dzieje. Ustawienie stanu tworzy żądanie nowego przerenderowania, ale nie zmienia tego stanu w już działającym kodzie. Dlatego score nadal wynosi 0 tuż po wywołaniu setScore(score + 1).

console.log(score);  // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score);  // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score);  // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score);  // 0

Możesz naprawić to, przekazując funkcję aktualizującą (ang. updater function) podczas ustawiania stanu. Zauważ, jak zastąpienie setScore(score + 1) przez setScore(s => s + 1) naprawia przycisk "+3". Dzięki temu możesz kolejkować wiele aktualizacji stanu.

import { useState } from 'react';

export default function Counter() {
  const [score, setScore] = useState(0);

  function increment() {
    setScore(s => s + 1);
  }

  return (
    <>
      <button onClick={() => increment()}>+1</button>
      <button onClick={() => {
        increment();
        increment();
        increment();
      }}>+3</button>
      <h1>Wynik: {score}</h1>
    </>
  )
}
button { display: inline-block; margin: 10px; font-size: 20px; }

Przeczytaj rozdział Kolejkowanie serii aktualizacji stanu, aby dowiedzieć się, jak kolejkować sekwencję aktualizacji stanu.

Aktualizowanie obiektów w stanie {/updating-objects-in-state/}

Stan może przechowywać dowolne wartości javascriptowe, w tym obiekty. Nie powinno się jednak bezpośrednio zmieniać obiektów i tablic, które przechowuje się w stanie Reacta. Zamiast tego, gdy chcesz zaktualizować obiekt lub tablicę, musisz stworzyć nowy obiekt (lub skopiować istniejący), a następnie zaktualizować stan, aby używał tej kopii.

Zazwyczaj używa się składni rozproszenia (ang. spread syntax) ..., aby skopiować obiekty i tablice, które chcesz zmienić. Na przykład, aktualizacja zagnieżdżonego obiektu może wyglądać tak:

import { useState } from 'react';

export default function Form() {
  const [person, setPerson] = useState({
    name: 'Niki de Saint Phalle',
    artwork: {
      title: 'Blue Nana',
      city: 'Hamburg',
      image: 'https://i.imgur.com/Sd1AgUOm.jpg',
    }
  });

  function handleNameChange(e) {
    setPerson({
      ...person,
      name: e.target.value
    });
  }

  function handleTitleChange(e) {
    setPerson({
      ...person,
      artwork: {
        ...person.artwork,
        title: e.target.value
      }
    });
  }

  function handleCityChange(e) {
    setPerson({
      ...person,
      artwork: {
        ...person.artwork,
        city: e.target.value
      }
    });
  }

  function handleImageChange(e) {
    setPerson({
      ...person,
      artwork: {
        ...person.artwork,
        image: e.target.value
      }
    });
  }

  return (
    <>
      <label>
        Imię:
        <input
          value={person.name}
          onChange={handleNameChange}
        />
      </label>
      <label>
        Tytuł:
        <input
          value={person.artwork.title}
          onChange={handleTitleChange}
        />
      </label>
      <label>
        Miasto:
        <input
          value={person.artwork.city}
          onChange={handleCityChange}
        />
      </label>
      <label>
        Obraz:
        <input
          value={person.artwork.image}
          onChange={handleImageChange}
        />
      </label>
      <p>
        <i>{person.artwork.title}</i>
        {' autorstawa '}
        {person.name}
        <br />
        (położone w mieście {person.artwork.city})
      </p>
      <img
        src={person.artwork.image}
        alt={person.artwork.title}
      />
    </>
  );
}
label { display: block; }
input { margin-left: 5px; margin-bottom: 5px; }
img { width: 200px; height: 200px; }

Jeśli kopiowanie obiektów w kodzie staje się uciążliwe, możesz użyć biblioteki takiej jak Immer, aby zmniejszyć ilość powtarzającego się kodu:

import { useImmer } from 'use-immer';

export default function Form() {
  const [person, updatePerson] = useImmer({
    name: 'Niki de Saint Phalle',
    artwork: {
      title: 'Blue Nana',
      city: 'Hamburg',
      image: 'https://i.imgur.com/Sd1AgUOm.jpg',
    }
  });

  function handleNameChange(e) {
    updatePerson(draft => {
      draft.name = e.target.value;
    });
  }

  function handleTitleChange(e) {
    updatePerson(draft => {
      draft.artwork.title = e.target.value;
    });
  }

  function handleCityChange(e) {
    updatePerson(draft => {
      draft.artwork.city = e.target.value;
    });
  }

  function handleImageChange(e) {
    updatePerson(draft => {
      draft.artwork.image = e.target.value;
    });
  }

  return (
    <>
      <label>
        Imię:
        <input
          value={person.name}
          onChange={handleNameChange}
        />
      </label>
      <label>
        Tytuł:
        <input
          value={person.artwork.title}
          onChange={handleTitleChange}
        />
      </label>
      <label>
        Miasto:
        <input
          value={person.artwork.city}
          onChange={handleCityChange}
        />
      </label>
      <label>
        Obraz:
        <input
          value={person.artwork.image}
          onChange={handleImageChange}
        />
      </label>
      <p>
        <i>{person.artwork.title}</i>
        {' autorstwa '}
        {person.name}
        <br />
        (położone w mieście {person.artwork.city})
      </p>
      <img
        src={person.artwork.image}
        alt={person.artwork.title}
      />
    </>
  );
}
{
  "dependencies": {
    "immer": "1.7.3",
    "react": "latest",
    "react-dom": "latest",
    "react-scripts": "latest",
    "use-immer": "0.5.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}
label { display: block; }
input { margin-left: 5px; margin-bottom: 5px; }
img { width: 200px; height: 200px; }

Przeczytaj rozdział Aktualizowanie obiektów w stanie, aby dowiedzieć się, jak poprawnie aktualizować obiekty.

Aktualizowanie tablic w stanie {/updating-arrays-in-state/}

Tablice są kolejnym rodzajem zmiennych obiektów javascriptowych, które można przechowywać w stanie i należy je traktować jako tylko do odczytu. Podobnie jak w przypadku obiektów, gdy chcesz zaktualizować tablicę przechowywaną w stanie, musisz stworzyć nową tablicę (lub skopiować istniejącą), a następnie ustawić stan, aby używał nowej tablicy:

import { useState } from 'react';

const initialList = [
  { id: 0, title: 'Wielkie brzuchy', seen: false },
  { id: 1, title: 'Księżycowy krajobraz', seen: false },
  { id: 2, title: 'Terakotowa armia', seen: true },
];

export default function BucketList() {
  const [list, setList] = useState(
    initialList
  );

  function handleToggle(artworkId, nextSeen) {
    setList(list.map(artwork => {
      if (artwork.id === artworkId) {
        return { ...artwork, seen: nextSeen };
      } else {
        return artwork;
      }
    }));
  }

  return (
    <>
      <h1>Lista dzieł sztuki</h1>
      <h2>Moja lista dzieł sztuki do zobaczenia:</h2>
      <ItemList
        artworks={list}
        onToggle={handleToggle} />
    </>
  );
}

function ItemList({ artworks, onToggle }) {
  return (
    <ul>
      {artworks.map(artwork => (
        <li key={artwork.id}>
          <label>
            <input
              type="checkbox"
              checked={artwork.seen}
              onChange={e => {
                onToggle(
                  artwork.id,
                  e.target.checked
                );
              }}
            />
            {artwork.title}
          </label>
        </li>
      ))}
    </ul>
  );
}

Jeśli kopiowanie tablic w kodzie staje się uciążliwe, możesz użyć biblioteki takiej jak Immer, aby zmniejszyć ilość powtarzającego się kodu:

import { useState } from 'react';
import { useImmer } from 'use-immer';

const initialList = [
  { id: 0, title: 'Wielkie brzuchy', seen: false },
  { id: 1, title: 'Księżycowy krajobraz', seen: false },
  { id: 2, title: 'Terakotowa armia', seen: true },
];

export default function BucketList() {
  const [list, updateList] = useImmer(initialList);

  function handleToggle(artworkId, nextSeen) {
    updateList(draft => {
      const artwork = draft.find(a =>
        a.id === artworkId
      );
      artwork.seen = nextSeen;
    });
  }

  return (
    <>
      <h1>Lista dzieł sztuki</h1>
      <h2>Moja lista dzieł sztuki do zobaczenia:</h2>
      <ItemList
        artworks={list}
        onToggle={handleToggle} />
    </>
  );
}

function ItemList({ artworks, onToggle }) {
  return (
    <ul>
      {artworks.map(artwork => (
        <li key={artwork.id}>
          <label>
            <input
              type="checkbox"
              checked={artwork.seen}
              onChange={e => {
                onToggle(
                  artwork.id,
                  e.target.checked
                );
              }}
            />
            {artwork.title}
          </label>
        </li>
      ))}
    </ul>
  );
}
{
  "dependencies": {
    "immer": "1.7.3",
    "react": "latest",
    "react-dom": "latest",
    "react-scripts": "latest",
    "use-immer": "0.5.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}

Przeczytaj rozdział Aktualizowanie tablic w stanie, aby dowiedzieć się, jak poprawnie aktualizować tablice.

Co dalej? {/whats-next/}

Przejdź do rozdziału Reagowanie na zdarzenia, aby zacząć zgłębiać ten temat strona po stronie!

Ewentualnie, jeśli już znasz te tematy, dlaczego nie przeczytać rozdziału Zarządzanie stanem?