Propsien välittäminen komponentille

React komponentit käyttävät propseja kommunikoidakseen toistensa välillä. Jokainen pääkomponentti voi välittää tietoa sen lapsikomponenteille antamalla niille propseja. Propsit saattavat muistuttaa HTML attribuuteista, mutta ne voivat välittää mitä tahansa JavaScript arvoa, kuten oliota, listoja ja funktioita.

Tulet oppimaan

  • Miten välittää propseja komponentille
  • Miten lukea propseja komponentista
  • Miten määritellä oletusarvoja propseille
  • Miten välittää JSX:ää komponenteille
  • Miten propsit muuttuvat ajan kanssa

Tuttuja propseja

Propsit ovat tietoa jota välität JSX tagille. Esimerkiksi className, src, alt, width ja height ovat muutamia propseja, joita voit välittää <img> tagille:

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

Propsit joita välität <img> tagille ovat esimääriteltyjä (ReactDOM mukautuu HTML standardiin). Mutta voit välittää mitä tahansa propseja omalle komponentillesi, kuten <Avatar>:lle, mukauttaaksesi sen. Tässä miten!

Propsien välittäminen komponentille

Seuraavassa koodissa Profile komponentti ei välitä yhtään propsia sen Avatar lapsikomponentille:

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

Voit antaa Avatar:lle propseja kahdessa vaiheessa.

1. Vaihe: Välitä propsi lapsikomponentille

Ensiksi välitä jokin propsi Avatar:lle. Esimerkiksi anna sille kaksi propsia: person (olio) ja size (numero):

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

Huomaa

Mikäli aaltosulkeet person= hämmentävät sinua, muista että ne ovat vain olioita JSX aaltosulkeiden sisällä.

Nyt voit lukea näitä propseja Avatar komponentin sisällä.

2. Vaihe: Lue propsit lapsikomponentin sisällä

Voit lukea nämä propsit listaamalla niiden nimet person, size pilkulla eroteltuna ({ and }) sisällä suoraan function Avatar jälkeen. Näin voit käyttää niitä Avatar koodin sisällä, kuten käyttäisit muuttujia.

function Avatar({ person, size }) {
// person and size are available here
}

Lisää vähän logiikkaa Avatar:lle, joka hyödyntää person ja size proppeja renderöinnissä, ja olet valmis.

Nyt voit määritellä Avatar:n renderöimään monella erilaisella tavalla eri propseilla. Kokeile muuttaa arvoja!

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

Propsien avulla voit ajatella pää- ja lapsikomponentteja erikseen. Esimerkiksi voit muuttaa person tai size propsia Profile:n sisällä ilman, että täytyy miettiä miten Avatar käyttää niitä. Samoin voit muuttaa miten Avatar käyttää näitä propseja ilman, että täytyy katsoa Profile koodia.

Voit ajatella propseja “säätiminä”, joita voit säätää. Niillä on sama rooli kuin argumenteilla on funktioissa—itse asiassa, propsit ovat ainoa argumentti komponenttiisi! React komponentit hyväksyvät yhden argumentin, props olion:

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

Useimmiten ei tarvitse kirjoittaa koko props oliota itsessään, vaan voit destrukturoida sen yksittäisiksi propseiksi.

Sudenkuoppa

Älä unohda { ja } aaltosulkeita ( ja ) sulkeiden sisällä kun määrität propseja:

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

Tätä syntaksia kutsutaan “destrukturoinniksi” ja se vastaa argumenttien lukemiseen funktiossa:

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

Oletusarvon määrittäminen propsille

Jos haluat antaa propsille oletusarvon johon turvautua kun arvoa ei ole määritelty, voit tehdä sen destrukturoinnissa laittamalla = ja oletusarvon sen jälkeen:

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

Nyt jos <Avatar person={...} /> renderöidään ilman size propsia, size asetetaan arvoon 100.

Oletusarvoa käytetään vain jos size propsi puuttuu tai jos välität size={undefined}. Mutta jos välität size={null} tai size={0}, oletusarvoa ei käytetä.

Propsien välittäminen JSX spread-syntaksilla

Joskus propsien välittäminen käy toistuvaksi:

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

Toistuvassa koodissa ei ole mitään väärää-se voi olla luettavempaa. Mutta ajoittain saatat arvostaa ytimekkyyttä. Jotkin komponentit välittävät kaikki niiden propsit niiden lapsikomponenteilleen, kuten tämä Profile tekee sen Avatar:lle. Koska se ei itse käytä suoraan yhtään propsia, voi olla järkevää käyttää lyhyttä “spread” syntaksia:

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

Tämä välittää kaikki Profile:n propsit Avatar:lle ilman jokaisen nimen listaamista.

Käytä spread-syntaksia hillitysti. Jos käytät sitä jokaisessa komponentissa, jotain on pielessä. Useimmiten se osoittaa, että sinun täytyisi jakaa komponenttisi osiin ja välittää JSX lapsina. Tästä lisää seuraavaksi!

JSX:n välittäminen lapsena

On yleistä upottaa selaimen sisäänrakennettuja tageja toisiinsa:

<div>
<img />
</div>

Joskus haluat upottaa omia komponentteja samalla tavalla:

<Card>
<Avatar />
</Card>

Kun upotat sisältöä JSX tagiin, pääkomponentti vastaanottaa sisällön propsina nimeltään children. Esimerkiksi Card komponentti vastaanottaa children propin, joka sisältää <Avatar /> komponentin ja renderöi sen diviin käärittynä:

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

Kokeile korvata <Card> komponentista <Avatar> jollain tekstillä nähdäksesi miten Card komponentti voi kääriä mitä vain sisältöä. Sen ei tarvitse “tietää” mitä renderöidään sen sisällä. Näet tätä tapaa käytettävän monissa paikoissa.

Voit ajatella komponenttia, jolla on children propsi kuin sillä olisi “aukko” joka voidaan “täyttää” sen pääkomponentista mielivaltaisella JSX:llä. Käytät children propsia usein visuaalisiin wrappereihin: paneeleihin, ruudukkoihin, jne.

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

Illustrated by Rachel Lee Nabors

Miten prosit muuttuvat ajan kanssa

Clock komponentti alla vastaanottaa kaksi propsia sen pääkomponentilta: color ja time. (Pääkomponentin koodi on jätetty pois koska se käyttää tilaa, johon emme vielä syvenny.)

Kokeile muuttaa väriä valintaruudusta alla:

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

Tämä esimerkki havainnollistaa, että komponentti voi vastaanottaa erilaisia propseja ajan saatossa. Propsit eivät aina ole staattisia! Tässä time propsi muuttuu joka sekunti ja color propsi muuttuu kun valitset toisen värin. Propsit kuvastavat komponentin dataa ajan kuluessa, ei ainoastaan alussa.

Propsit ovat kuitenkin muuttumattomia (engl. immutable). Kun komponentin täytyy muuttaa sen propseja (esimerkiksi vastauksena käyttäjän toimintoon tai uuteen dataan), sen täytyy “kysyä” sen pääkomponentilta antaakseen sille eri propsit-uuden olion! Sen vanhat propsit sitten heitetään pois ja lopulta JavaScript moottori suorittaa roskienkeruun palauttaen niiden käyttämän muistin.

Älä yritä “muuttaa propseja”. Kun sinun täytyy vastata käyttäjän syötteeseen (kuten värin muutokseen), täytyy “asettaa tila”, josta voit oppia lisää lukemalla Tila: Komponentin muisti.

Kertaus

  • Välittääksesi propseja, lisää ne JSX:ään kuten tekisit HTML attribuuteilla.
  • Lukeaksesi propseja, käytä function Avatar({ person, size }) destrukturointi -syntaksia.
  • Voit määritellä oletusarvon kuten size = 100, jota käytetään puuttuvissa sekä undefined propseissa.
  • Voit välittää kaikki propsit käyttämällä <Avatar {...props} /> JSX spread syntaksia, mutta älä käytä sitä liikaa!
  • Sisäkkäinen JSX koodi kuten <Card><Avatar /></Card> ilmenee Card komponentin children propsina.
  • Propsit ovat vain-luku snapshotteja ajasta: joka renderillä se vastaanottaa uuden version propseista.
  • Et voi muuttaa propseja. Kun tarvitset interaktiivisuutta, käytä tilaa.

Haaste 1 / 3:
Erota komponentti

Tämä Gallery komponentti sisältää samanlaista merkintäkoodia kahdelle profiilille. Luo Profile komponentti vähentääksesi koodin toistoa. Sinun täytyy päättää mitä propseja välität sille.

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

export default function Gallery() {
  return (
    <div>
      <h1>Notable Scientists</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>Profession: </b> 
            physicist and chemist
          </li>
          <li>
            <b>Awards: 4 </b> 
            (Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal, Matteucci Medal)
          </li>
          <li>
            <b>Discovered: </b>
            polonium (chemical 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>Profession: </b> 
            geochemist
          </li>
          <li>
            <b>Awards: 2 </b> 
            (Miyake Prize for geochemistry, Tanaka Prize)
          </li>
          <li>
            <b>Discovered: </b>
            a method for measuring carbon dioxide in seawater
          </li>
        </ul>
      </section>
    </div>
  );
}