Prosleđivanje props-a u komponentu

React komponente koriste props da bi međusobno komunicirale. Svaka roditeljska komponenta može proslediti informacije svojoj deci tako što im daje props. Props-i vas možda podsećaju na HTML atribute, ali pomoću njih možete proslediti bilo koju JavaScript vrednost, uključujući objekte, nizove i funkcije.

Naučićete:

  • Kako da prosledite props-e u komponentu
  • Kako da pročitate props-e u komponenti
  • Kako da definišete default vrednosti za props
  • Kako da prosledite JSX komponenti
  • Kako se props-i menjaju tokom vremena

Poznati props-i

Props-i su informacije koje prosleđujete u JSX tag. Na primer, className, src, alt, width i height su samo neki od props-a koje možete proslediti u <img>:

function Avatar() {
  return (
    <img
      className="avatar"
      src="https://i.imgur.com/1bX5QH6.jpg"
      alt="Lin Lanying"
      width={100}
      height={100}
    />
  );
}

export default function Profile() {
  return (
    <Avatar />
  );
}

Props-i koje prosleđujete u <img> tag su predefinisani (ReactDOM se prilagođava HTML standardu). Vi možete proslediti bilo koji props vašim komponentama, poput <Avatar>-a, da biste ih prilagodili svojim potrebama. Evo i kako!

Prosleđivanje props-a u komponentu

U ovom primeru, Profile komponenta ne prosleđuje nikakav props svom detetu, Avatar komponenti:

export default function Profile() {
return (
<Avatar />
);
}

U dva koraka možete dodati props u Avatar.

Korak 1: Proslediti props u dete komponentu

Prvo, prosledite props u Avatar. Na primer, prosledimo dva props-a: person (objekat) i size (broj):

export default function Profile() {
return (
<Avatar
person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
size={100}
/>
);
}

Napomena

Ako vas duple vitičaste zagrade nakon person= zbunjuju, setite se da one samo predstavljaju objekat unutar JSX vitičastih zagrada.

Sada ove props-e možete pročitati unutar Avatar komponente.

Korak 2: Pročitati props unutar dečje komponente

Možete pročitati ove props-e izlistavanjem njihovih imena person, size odvojenih zarezima unutar ({ i }) odmah nakon function Avatar. Ovo vam omogućava da ih koristite unutar Avatar funkcije, kao bilo koju drugu promenljivu.

function Avatar({ person, size }) {
// person i size su dostupni ovde
}

Dodajte neku logiku u Avatar koja će koristiti person i size props-e za renderovanje i gotovi ste.

Sada možete konfigurisati Avatar da renderuje različite stvari uz pomoć različitih props-a. Probajte da menjate vrednosti!

import { getImageUrl } from './utils.js';

function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

export default function Profile() {
  return (
    <div>
      <Avatar
        size={100}
        person={{ 
          name: 'Katsuko Saruhashi', 
          imageId: 'YfeOqp2'
        }}
      />
      <Avatar
        size={80}
        person={{
          name: 'Aklilu Lemma', 
          imageId: 'OKS67lh'
        }}
      />
      <Avatar
        size={50}
        person={{ 
          name: 'Lin Lanying',
          imageId: '1bX5QH6'
        }}
      />
    </div>
  );
}

Props-i vam omogućavaju da odvojeno razmišljate o roditeljskim i dečjim komponentama. Na primer, možete promeniti person ili size props unutar Profile-a bez potrebe da razmišljate kako ih Avatar koristi. Slično tome, možete promeniti kako Avatar koristi te props-e bez gledanja u Profile.

Props-e možete zamisliti kao “dugmiće” koje možete podešavati. Oni igraju istu ulogu kao i argumenti u funkcijama—u suštini, props-i jesu jedini argument u vašoj komponenti! Funckije React komponenata prihvataju samo jedan argument, props objekat:

function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}

Uglavnom vam neće biti potreban ceo props objekat, već ćete ga dekonstruisati na pojedinačne props-e.

Pitfall

Nemojte propustiti par vitičastih zagrada unutar ( i ) prilikom deklaracije props-a:

function Avatar({ person, size }) {
// ...
}

Ova sintaksa se naziva “dekonstruisanje” i jednaka je čitanju polja od parametra funkcije:

function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}

Definisanje default vrednosti za prop

Ako želite da zadate default vrednost prop-u, koja će se koristiti kada vrednost nije definisana, to možete uraditi pomoću dekonstruisanja stavljajući = i default vrednost odmah nakon parametra:

function Avatar({ person, size = 100 }) {
// ...
}

Sada, ako se <Avatar person={...} /> renderuje bez size prop-a, size će biti setovano na 100.

Default vrednost je upotrebljena samo ako izostavite size prop ili ako prosledite size={undefined}. Ali, ako prosledite size={null} ili size={0}, default vrednost neće biti upotrebljena.

Prosleđivanje props-a sa JSX spread sintaksom

Ponekad se prosleđivanje props-a može ponavljati:

function Profile({ person, size, isSepia, thickBorder }) {
return (
<div className="card">
<Avatar
person={person}
size={size}
isSepia={isSepia}
thickBorder={thickBorder}
/>
</div>
);
}

Nema ništa loše u ponavljanju koda—ponekad može biti čitljivije. Ali, nekada vam je potrebna sažetost. Neke komponente prosleđuju sve svoje props-e deci, kao što to Profile radi sa Avatar-om. Pošto one direktno ne koriste nijedan svoj prop, ima smisla upotrebiti koncizniju “spread” sintaksu:

function Profile(props) {
return (
<div className="card">
<Avatar {...props} />
</div>
);
}

Ovo prosleđuje sve props-e od Profile-a u Avatar bez izlistavanja njihovih imena pojedinačno.

Koristite spread sintaksu odmereno. Ako je koristite u svakoj komponenti, nešto nije u redu. To često označava da biste trebali podeliti komponente i proslediti decu kao JSX. Više u nastavku!

Prosleđivanje JSX-a kao dece

Ugnježdavanje ugrađenih (built-in) tag-ova je često:

<div>
<img />
</div>

Ponekad želite da ugnjezdite vaše komponente na isti način:

<Card>
<Avatar />
</Card>

Kada ugnjezdite sadržaj unutar JSX tag-a, roditeljska komponenta će primiti taj sadržaj kroz prop po imenu children. Na primer, Card komponenta ispod će primiti children prop setovan na <Avatar /> i renderovati ga u wrapper div-u:

import Avatar from './Avatar.js';

function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{ 
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2'
        }}
      />
    </Card>
  );
}

Pokušajte da promenite <Avatar> unutar <Card>-a sa nekim tekstom da biste videli kako Card komponenta može da obmota bilo koji ugnježdeni sadržaj. Ona ne mora da “zna” šta će biti renderovano unutar nje. Videćete ovaj fleksibilni obrazac na mnogim mestima.

Komponentu sa children prop možete zamisliti kao da ima “šupljinu” koja će biti “popunjena” u njenim roditeljskim komponentama sa proizvoljnim JSX-om. Često ćete koristiti children prop za vizuelne wrapper-e: panel-e, grid-ove, itd.

A puzzle-like Card tile with a slot for "children" pieces like text and Avatar

Illustrated by Rachel Lee Nabors

Kako se props-i menjaju tokom vremena

Clock komponenta ispod prima dva props-a od svog roditelja: color i time. (Kod roditeljske komponente je izostavljen zato što koristi state, u koji nećemo zalaziti još uvek.)

Pokušajte da promenite boju u primeru ispod:

export default function Clock({ color, time }) {
  return (
    <h1 style={{ color: color }}>
      {time}
    </h1>
  );
}

Ovaj primer ilustruje kako komponenta može primiti različite props-e tokom vremena. Props-i nisu uvek statički! Ovde se time prop menja svake sekunde, a color prop se menja kada odaberete drugu boju. Props-i odražavaju podatke u komponenti u bilo kom trenutku, a ne samo na početku.

Međutim, props-i su immutable—pojam koji u informatici označava nešto “nepromenljivo”. Kada komponenta treba da promeni svoje props-e (na primer, nakon interakcije korisnika ili na osnovu novih podataka), moraće da “pita” svog roditelja da joj prosledi druge props-e—novi objekat! Njeni stari props-i će biti odbačeni, a JavaScript će se u nekom trenutku pobrinuti da oslobodi memoriju koju su zauzeli.

Ne pokušavajte da “menjate props”. Kada želite da reagujete na korisnički input (kao što je promena odabrane boje), moraćete da “set-ujete state”, što možete naučiti u State: Memorija komponente.

Recap

  • Da biste prosledili props, dodajte ih u JSX, kao što bi to uradili sa HTML atributima.
  • Da biste pročitali props, koristite function Avatar({ person, size }) sintaksu dekonstruisanja.
  • Možete definisati default vrednost poput size = 100, koja se koristi za izostavljene i undefined props-e.
  • Možete proslediti sve props-e sa <Avatar {...props} /> JSX spread sintaksom, ali nemojte je previše koristiti!
  • Ugnježdeni JSX poput <Card><Avatar /></Card> će se pojaviti u Card komponenti kao children prop.
  • Props-i su read-only snapshot-ovi u vremenu: svako renderovanje prima novu verziju props-a.
  • Ne možete menjati props-e. Kada vam je potrebna interaktivnost, trebate da setujete state.

Izazov 1 od 3:
Izdvojiti komponentu

Ova Gallery komponenta sadrži veoma sličan markup za dva profila. Izdvojite Profile komponentu kako biste smanjili ponavljanje. Moraćete da izaberete koje props-e da joj prosledite.

import { getImageUrl } from './utils.js';

export default function Gallery() {
  return (
    <div>
      <h1>Značajni naučnici</h1>
      <section className="profile">
        <h2>Maria Skłodowska-Curie</h2>
        <img
          className="avatar"
          src={getImageUrl('szV5sdG')}
          alt="Maria Skłodowska-Curie"
          width={70}
          height={70}
        />
        <ul>
          <li>
            <b>Profesija: </b> 
            fizičar i hemičar
          </li>
          <li>
            <b>Nagrade: 4 </b> 
            (Nobelova nagrada za fiziku, Nobelova nagrada za hemiju, Davy medalja, Matteucci medalja)
          </li>
          <li>
            <b>Otkrića: </b>
            polonijum (hemijski element)
          </li>
        </ul>
      </section>
      <section className="profile">
        <h2>Katsuko Saruhashi</h2>
        <img
          className="avatar"
          src={getImageUrl('YfeOqp2')}
          alt="Katsuko Saruhashi"
          width={70}
          height={70}
        />
        <ul>
          <li>
            <b>Profesija: </b> 
            geohemičar
          </li>
          <li>
            <b>Nagrade: 2 </b> 
            (Miyake nagrada za geohemiju, Tanaka nagrada)
          </li>
          <li>
            <b>Otkrića: </b>
            metoda za merenje ugljen-dioksida u morskoj vodi
          </li>
        </ul>
      </section>
    </div>
  );
}