Перадача пропсаў у кампанент

Для камунікацыі між сабой кампаненты React выкарыстоўваць пропсы. Кожны бацькоўскі кампанент можа перадаваць некаторую інфармацыю даччыным, задаючы ім пропсы. Пропсы падобныя на атрыбуты ў HTML, але ў іх вы можаце перадаваць любыя JavaScript значэнні, уключаючы аб’екты, масівы, функцыі.

You will learn

  • Як перадаваць пропсы ў кампанент
  • Як атрымліваць пропсы ў кампаненце
  • Як задаваць прадвызначаныя значэнні для пропсаў
  • Як перадаць JSX у кампанент
  • Як пропсы змяняюцца з часам

Знаёмыя пропсы

Пропсы — гэта інфармацыя, што вы перадаяце ў JSX тэг. Напрыклад: className, src, alt, width, і height — некаторыя пропсы, якія можна перадаць у <img>:

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

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

Пропсы, якія можна перадаць у тэг <img> прадвызначаныя (ReactDOM адпавядае стандарту HTML). Але ва ўласныя кампаненты, такія як <Avatar>, вы можаце перадаваць любыя пропсы, каб іх дапасоўваць. Вось як гэта зрабіць!

Перадача пропсаў у кампаненты

У гэтым кодзе кампанент Profile не перадае аніводнага пропса свайму даччынаму кампаненту Avatar:

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

Вы можаце дадаць новыя пропсы для Avatar у два этапы.

Крок 1: Перадаць пропсы даччынаму кампаненту

Па-першае, перадайце пропсы ў Avatar. Напрыклад, давайце перададзім два пропсы: person (аб’ект) і size (лічба):

export default function Profile() {
return (
<Avatar
person={{ name: 'Лінь Ланьін', imageId: '1bX5QH6' }}
size={100}
/>
);
}

Note

Калі падвойныя фігурныя дужкі пасля person= вас блытаюць, напамінаем, што гэта ўсяго толькі аб’екты ўнутры фігурных дужак JSX.

Цяпер вы можаце прачытаць гэтыя пропсы ў кампаненце Avatar.

Крок 2: прачытайце пропсы ў даччыным кампаненце

Вы можаце прачытаць гэтыя пропсы, пералічыўшы іх назвы person, size цераз коску ўнутры ({ і }) адразу пасля function Avatar. Гэта дазволіць вам выкарыстоўваць іх у Avatar, нібы яны пераменныя.

function Avatar({ person, size }) {
// person і size цяпер даступныя тут
}

Нарэшце, дадайце некаторую логіку да Avatar, скарыстаўшы пропсы person і size для рэндэрынгу.

Цяпер з дапамогай пропсаў вы можаце змяняць канфігурацыю Avatar, каб рэндэрыць яго па-рознаму. Паспрабуйце пагуляцца са значэннямі!

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: 'Кацуко Сарухасі', 
          imageId: 'YfeOqp2'
        }}
      />
      <Avatar
        size={80}
        person={{
          name: 'Аклілу Лема', 
          imageId: 'OKS67lh'
        }}
      />
      <Avatar
        size={50}
        person={{ 
          name: 'Лiнь Ланьін',
          imageId: '1bX5QH6'
        }}
      />
    </div>
  );
}

Пропсы дазваляюць вам успрымаць бацькоўскі і даччыны кампаненты незалежнымі адзін ад аднаго. Напрыклад, вы можаце змяніць пропсы person ці size унутры кампанента Profile нават не задумваючыся аб тым, як кампанент Avatar іх выкарыстоўвае. Аналагічна, вы можаце змяняць тое, як Avatar апрацоўвае гэтыя пропсы, не гледзячы на логіку кампанента Profile.

Вы можаце разглядаць пропсы як «рычажкі», якімі вы можаце рэгуляваць свой кампанент. Яны выконваюць тую ролю, што і аргументы ў функцыі. Да таго ж, пропсы — адзіны аргумент, які перадаецца ў кампанент! Функцыянальны кампанент React прымае толькі адзін кампанент, а іменна аб’ект props:

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

Звычайна вам не будзе патрэбны сам аб’ект props, прасцей будзе разабраць на асобныя пропсы.

Pitfall

Не забывайце пра пару фігурных дужак { і } унутры дужак ( і ), калі вызначаеце пропсы:

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

дадзены сінтаксіс называецца «дэструктурызацыяй» — гэта як чытаць уласцівасці з параметра функцыі:

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

Прадвызначаныя значэнні для пропсаў

Калі вы хочаце задаць прадвызначанае значэнне, якое будзе выкарыстоўвацца, калі пропс не вызначаны, вы можаце дадаць = і пасля яго прадвызначанае значэнне:

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

Цяпер, калі <Avatar person={...} /> будзе адрэндэрына без пропса size, ягоным значэннем будзе 100.

Прадвызначанае значэнне будзе выкарыстана толькі калі пропс size адсутнічае, ці калі зададзены як size={undefined}. Такія варыянты, як size={null} ці size={0} не будуць замененыя на прадвызначанае значэнне.

Перадача пропсаў з выкарыстаннем сінтаксіса разгортвання

Часам пропсы пачынаюць шмат паўтарацца:

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

Няма нічога дрэннага ў тым, каб паўтараць імёны пропсаў — такі код будзе больш зразумелым. Але магчыма з часам вам захочацца зрабіць яго лаканічней. Некаторыя кампаненты перадаюць свае пропсы даччыным, напрыклад як кампанент Profile перадае іх кампаненту Avatar. Так як кампанент не выкарыстоўвае ўласныя пропсы сам, ёсць сэнс скарыстаць больш лаканічны сінтаксіс разгортвання:

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

Гэта перадасць усе пропсы кампанента Profile кампаненту Avatar без іх пераліку спісам.

Карыстайцеся аператарам разгортвання разумна. Калі вы пачынаеце выкарыстоўваць яго ў кожным кампаненце, вы штосьці робіце не так. Часта гэта прыкмета таго, што варта раздзяліць кампаненты і перадаць даччыныя ў выглядзе JSX. Далей разгледзім як гэта зрабіць!

Перадача JSX у якасці даччыных элементаў

Звычайная практыка — укладаць у стандартны набор тэгаў іншыя тэгі:

<div>
<img />
</div>

Часам вам можа спатрэбіцца зрабіць тое ж самае і з уласнымі кампанентамі:

<Card>
<Avatar />
</Card>

Калі вы ўкладаеце штосьці ў JSX тэг, бацькоўскі кампанент атрымае кантэнт у якасці пропса пад назвай children. Напрыклад, кампанент Card з прыкладу ніжэй атрымае пропс children, у якім будзе <Avatar />, і адрэндэрыць яго ўнутры div:

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: 'Кацуко Сарухасі',
          imageId: 'YfeOqp2'
        }}
      />
    </Card>
  );
}

Паспрабуйце замяніць <Avatar> унутры <Card> на які-небудзь тэкст каб паглядзець як кампанент Card можа працаваць з розным укладзеным кантэнтам. Яму не трэба «ведаць», што будзе адрэндэрына ўнутры яго. Падобны гібкі шаблон вы яшчэ шмат дзе пабачыце.

Паспрабуйце разгледзіць кампанент з пропсам children як «дзірку», якую бацькоўскі кампанент можа запоўніць разметкай JSX. Вам часта давядзецца выкарыстоўваць пропс children для візуальных абгортак: панэлей, сетак і г.д.

Плітка, падобная на пазл, са слотам «children» у які падыходзяць кавалкі «Text» і «Avatar»

Illustrated by Rachel Lee Nabors

Як пропсы змяняюцца з часам

Кампанент Clock ніжэй атрымлівае два пропсы ад бацькоўскага кампанента: color і time (бацькоўскі кампанент не разглядаецца, бо ён выкарыстоўвае стан, у падрабязнасці чаго мы яшчэ не паглыналіся).

Паспрабуйце змяніць колер у прыкладзе ніжэй:

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

Дадзены прыклад адлюстроўвае, што пропсы, якія кампанент атрымлівае, могуць змяняцца з часам. Пропсы не заўсёды статычныя! Тут, напрыклад, пропс time змяняецца кожную секунду, а пропс color змяняецца падчас выбару іншага колеру. Пропсы змяшчаюць даныя кампанента ў канкрэтны момант, а не толькі ў момант першага рэндэру.

Не гледзячы на гэта, пропсы нязменныя — гэты тэрмін азначае аб’ект, які не можа змяняцца пасля стварэння. Калі кампаненту трэба змяніць пропс (напрыклад, у адказ на ўзаемадзеянне з боку карыстальніка ці новыя даныя), яму давядзецца «папрасіць» бацькоўскі кампанент перадаць новы іншы пропс — новаствораны аб’ект! Старыя пропсы будуць адкінутыя, і ў рэшце рэшт рухавік JavaScript выдаліць іх з памяці.

**Не спрабуйце «змяняць пропсы». **Калі вы хочаце адрэагаваць на ўведзеныя карыстальнікам даныя (напрыклад, змену колеру), вам спатрэбіцца «задаць стан». Падрабязней пра гэта вы можаце даведацца на старонцы «Стан: Памяць кампанента.»

Recap

  • Каб перадаць пропсы, дадайце іх у JSX як бы вы дадалі атрыбуты ў HTML.
  • Каб прачытаць пропсы, скарыстайце дэструктурызацыйны сінтаксіс: function Avatar({ person, size }).
  • Вы можаце задаць прадвызначанае значэнне для пропса: size = 100, яно будзе скарыстана, калі пропс адсутнічае ці ягонае значэнне undefined.
  • Вы можаце перадаць усе пропсы даччынаму элементу, скарыстаўшы сінтаксіс разгортвання: <Avatar {...props} />. Але не выкарыстоўвайце яго зашмат!
  • Укладзены JSX, такі як <Card><Avatar /></Card>, з’явіцца ў кампаненце Card у якасці пропсы children.
  • Пропсы нязменны і адлюстроўваюць толькі цяперашні стан: пры кожны рэндэры кампанент атрымлівае новую версію пропсаў.
  • Вы не можаце змяняць пропсы. Калі вам патрэбная інтэрактыўнасць, вам спатрэбіцца задаць стан.

Challenge 1 of 3:
Вынесіце кампанент

Дадзены кампанент Gallery змяшчае вельмі падобную разметку для двух профіляў. Вынесіце яе ў кампанент Profile, каб паменшыць колькасць кода, які паўтараецца. Вам давядзецца выбраць, якія пропсы вам спатрэбіцца перадаваць.

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

export default function Gallery() {
  return (
    <div>
      <h1>Выбітныя навукоўцы</h1>
      <section className="profile">
        <h2>Марыя Складоўская-Кюры</h2>
        <img
          className="avatar"
          src={getImageUrl('szV5sdG')}
          alt="Марыя Складоўская-Кюры"
          width={70}
          height={70}
        />
        <ul>
          <li>
            <b>Сфера дзейнасці: </b> 
            фізіка і хімія
          </li>
          <li>
            <b>Нагароды: 4 </b> 
            (Нобелеўская прэмія па фізіцы, Нобелеўская прэмія па хіміі, медаль Дэві, медаль Матэуччы)
          </li>
          <li>
            <b>Адкрыццё: </b>
            Палоній (хімічны элемент)
          </li>
        </ul>
      </section>
      <section className="profile">
        <h2>Кацуко Сарухасі</h2>
        <img
          className="avatar"
          src={getImageUrl('YfeOqp2')}
          alt="Кацуко Сарухасі"
          width={70}
          height={70}
        />
        <ul>
          <li>
            <b>Сфера дзейнасці: </b>
            геахімія
          </li>
          <li>
            <b>Нагароды: 2 </b> 
            (прыз Міякэ па геахіміі, прыз Танака)
          </li>
          <li>
            <b>Адкрыццё: </b>
            метад вымярэння вуглякіслага газу ў марской вадзе
          </li>
        </ul>
      </section>
    </div>
  );
}