Dodavanje interaktivnosti

Neke stvari na ekranu se update-uju kao odgovor na korisnički unos. Na primer, klik na galeriju slika menja aktivnu sliku. U React-u, podaci koji se menjaju tokom vremena nazivaju se state. Možete dodati state bilo kojoj component-i i update-ovati je po potrebi. U ovom poglavlju naučićete kako da pišete component-e koji obrađuju interakcije, update-uju svoj state i prikazuju različite output-e tokom vremena.

Odgovaranje na event-e

React vam omogućava da dodate event handler-e u vaš JSX. Event handler-i su vaše sopstvene funkcije koje će se pokrenuti kao odgovor na korisničke interakcije, poput klika, prelaženja mišem, fokusiranja na form input-e i tako dalje.

Ugrađene component-e poput <button> podržavaju samo ugrađene browser event-e poput onClick. Međutim, možete kreirati i sopstvene component-e i njihovim event handler prop-ovima dati bilo koja aplikacijski specifična imena koja želite.

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

function Toolbar({ onPlayMovie, onUploadImage }) {
  return (
    <div>
      <Button onClick={onPlayMovie}>
        Play Movie
      </Button>
      <Button onClick={onUploadImage}>
        Upload Image
      </Button>
    </div>
  );
}

function Button({ onClick, children }) {
  return (
    <button onClick={onClick}>
      {children}
    </button>
  );
}

Ready to learn this topic?

Pročitajte Odgovaranje na Event-e da biste naučili kako da dodate event handler-e.

Read More

State: memorija component-e

Component-e često moraju da promene ono što je prikazano na ekranu kao rezultat neke interakcije. Kucanje u formu treba da update-uje polje za unos, klik na “sledeće” u karuselu slika treba da promeni prikazanu sliku, klik na “kupi” stavlja proizvod u korpu. Component-e moraju da “pamte” određene stvari: trenutnu vrednost unosa, trenutnu sliku, korpu za kupovinu. U React-u, ova vrsta memorije specifična za component-e naziva se state.

Možete dodati state component-i pomoću Hook-a useState. Hook-ovi su specijalne funkcije koje omogućavaju vašim component-ama da koriste React funkcionalnosti (state je jedna od tih funkcionalnosti). Hook useState vam omogućava da deklarišete varijablu state-a. On prima inicijalni state i vraća par vrednosti: trenutni state i funkciju za setovanje state-a koja vam omogućava da ga update-ujete.

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

Here is how an image gallery uses and updates state on click:

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}>
        Next
      </button>
      <h2>
        <i>{sculpture.name} </i>
        by {sculpture.artist}
      </h2>
      <h3>
        ({index + 1} of {sculptureList.length})
      </h3>
      <button onClick={handleMoreClick}>
        {showMore ? 'Hide' : 'Show'} details
      </button>
      {showMore && <p>{sculpture.description}</p>}
      <img
        src={sculpture.url}
        alt={sculpture.alt}
      />
    </>
  );
}

Ready to learn this topic?

Pročitajte State: Memorija Component-e kako biste naučili kako da zapamtite vrednost i update-ujete je prilikom interakcije.

Read More

Render i commit

Pre nego što se vaše component-e prikažu na ekranu, React mora da ih render-uje. Razumevanje koraka u ovom procesu pomoći će vam da razmislite o tome kako se vaš kod izvršava i da objasnite njegovo ponašanje.

Zamislite da su vaše component-e kuvari u kuhinji, koji pripremaju ukusna jela od sastojaka. U ovom scenariju, React je konobar koji prenosi narudžbine od gostiju i donosi im njihova jela. Ovaj proces naručivanja i posluživanja UI-a ima tri koraka:

  1. Pokretanje render-a (prenos narudžbine gosta u kuhinju)
  2. Render-ovanje component-e (priprema narudžbine u kuhinji)
  3. Commit-ovanje u DOM (postavljanje narudžbine na sto)
  1. React kao konobar u restoranu, prenosi narudžbine od korisnika i dostavlja ih u Component-u Kitchen.
    Trigger
  2. Šef kuhinje za Card daje React-u svežu Card component-u.
    Render
  3. React donosi Card korisniku za njihov sto.
    Commit

Illustrated by Rachel Lee Nabors

Ready to learn this topic?

Pročitajte Render i Commit kako biste naučili lifecycle jednog UI update-a.

Read More

State kao snapshot

Za razliku od običnih JavaScript varijabli, React state se ponaša više kao snapshot. Njegovo postavljanje ne menja već postojeću state varijablu, već umesto toga pokreće re-render. Ovo može biti iznenađujuće na početku!

console.log(count); // 0
setCount(count + 1); // Request a re-render with 1
console.log(count); // Still 0!

Ovo ponašanje vam pomaže da izbegnete suptilne greške. Evo male aplikacije za ćaskanje. Pokušajte da pogodite šta će se desiti ako prvo pritisnete “Pošalji”, a zatim promenite primaoca na Bob. Čije ime će se pojaviti u alert pet sekundi kasnije?

import { useState } from 'react';

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

  function handleSubmit(e) {
    e.preventDefault();
    setTimeout(() => {
      alert(`Poruka ${message} za ${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">Send</button>
    </form>
  );
}

Ready to learn this topic?

Pročitajte State kao Snapshot da biste saznali zašto state izgleda “fiksno” i nepromenljivo unutar event handler-a.

Read More

Redosled serijskih update-ova state-a

Ova component-a ima grešku: klikom na dugme “+3” rezultat se povećava samo jednom.

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>Score: {score}</h1>
    </>
  )
}

State kao Snapshot objašnjava zašto se ovo dešava. Postavljanje state-a traži novo render-ovanje, ali ne menja njegovu vrednost u kodu koji se već izvršava. Tako score nastavlja da ima vrednost 0 odmah nakon što pozovete 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žete ovo popraviti prosleđivanjem updater funkcije kada postavljate state. Obratite pažnju kako zamena setScore(score + 1) sa setScore(s => s + 1) rešava problem dugmeta “+3”. Ovo vam omogućava da redom dodate više update-ova state-a u redosled.

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>Score: {score}</h1>
    </>
  )
}

Ready to learn this topic?

Pročitajte Redosled serije state update-ova](/learn/queueing-a-series-of-state-updates) kako biste naučili kako da postavite redosled update-ova state-a.

Read More

Update-ovanje objekata u state-u

State može sadržati bilo koju vrstu JavaScript vrednosti, uključujući objekte. Međutim, ne bi trebalo direktno menjati objekte i array-e koje držite u React state-u. Umesto toga, kada želite da update-ujete objekat ili array, potrebno je da kreirate novi (ili napravite kopiju postojećeg) i zatim update-ujete state kako bi koristio tu kopiju.

Obično ćete koristiti ... spread sintaksu za kopiranje objekata i array-a koje želite da promenite. Na primer, update-ovanje ugnježdenog objekta može izgledati ovako:

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>
        Name:
        <input
          value={person.name}
          onChange={handleNameChange}
        />
      </label>
      <label>
        Title:
        <input
          value={person.artwork.title}
          onChange={handleTitleChange}
        />
      </label>
      <label>
        City:
        <input
          value={person.artwork.city}
          onChange={handleCityChange}
        />
      </label>
      <label>
        Image:
        <input
          value={person.artwork.image}
          onChange={handleImageChange}
        />
      </label>
      <p>
        <i>{person.artwork.title}</i>
        {' by '}
        {person.name}
        <br />
        (located in {person.artwork.city})
      </p>
      <img
        src={person.artwork.image}
        alt={person.artwork.title}
      />
    </>
  );
}

Ako kopiranje objekata u kodu postane zamorno, možete koristiti biblioteku poput Immer kako biste smanjili količinu ponavljajućeg koda:

{
  "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"
  },
  "devDependencies": {}
}

Ready to learn this topic?

Pročitajte Update-ovanje Objekata u State-u kako biste naučili kako pravilno update-ovati objekte.

Read More

Update-ovanje array-a u state-u

Array-i su još jedan tip promenljivih JavaScript objekata koje možete čuvati u state-u i koje treba tretirati kao read-only. Kao i kod objekata, kada želite da update-ujete array koji se nalazi u state-u, potrebno je da kreirate novi (ili napravite kopiju postojećeg), a zatim postavite state da koristi taj novi array:

import { useState } from 'react';

const initialList = [
  { id: 0, title: 'Big Bellies', seen: false },
  { id: 1, title: 'Lunar Landscape', seen: false },
  { id: 2, title: 'Terracotta Army', 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>Art Bucket List</h1>
      <h2>My list of art to see:</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>
  );
}

Ako pravljenje kopija array-a u kodu postane zamorno, možete koristiti biblioteku kao što je Immer da smanjite ponavljanje koda:

{
  "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"
  },
  "devDependencies": {}
}

Ready to learn this topic?

Pročitajte Update-ovanje Array-a u State-u da biste naučili kako pravilno da update-ujete array-e.

Read More

Šta je sledeće?

Pređite na Reagovanje na Event-e da biste počeli da čitate ovo poglavlje stranicu po stranicu!

Ili, ako ste već upoznati sa ovim temama, zašto ne biste pročitali Upravljanje State-om?