Умоўны рэндэрынг
Вашым кампанентам часта трэба будзе адлюстроўваць розныя рэчы ў залежнасці ад розных умоў. У React вы можаце ўмоўна рэндэрыць JSX, выкарыстоўваючы такія JavaScript аператары, як if
, &&
і ?:
.
You will learn
- Як вярнуць розны JSX у залежнасці ад умовы
- Як у залежнасці ад умоў уключаць або выключаць частку JSX
- Распаўсюджаныя скарачэнні сінтаксісу ўмоўных выразаў, з якімі вы сутыкняцеся ў праектах на React.
Умоўнае вяртанне JSX
Дапусцім, у вас ёсць кампанент PackingList
, які рэндэрыць некалькі элементаў Item
, якія могуць быць пазначаны як упакаваныя ці не:
function Item({ name, isPacked }) { return <li className="item">{name}</li>; } export default function PackingList() { return ( <section> <h1>Спіс рэчаў Салі Райд</h1> <ul> <Item isPacked={true} name="Касмічны скафандр" /> <Item isPacked={true} name="Шлем з залатым лістом" /> <Item isPacked={false} name="Фота Тэма" /> </ul> </section> ); }
Звярніце ўвагу, што ў некаторых кампанентаў Item
пропс isPacked
мае значэнне true
замест false
. Калі isPacked={true}
, мы хочам дадаць галачку(✅) да спакаваных рэчаў.
Вы можаце зрабіць гэта з дапамогай канструкцыі if
/else
такім чынам:
if (isPacked) {
return <li className="item">{name} ✅</li>;
}
return <li className="item">{name}</li>;
Калі пропс isPacked
мае значэнне true
, гэты код верне іншае дрэва JSX. Разам з гэтай зменай, некаторыя элементы атрымаюць галачку ў канцы:
function Item({ name, isPacked }) { if (isPacked) { return <li className="item">{name} ✅</li>; } return <li className="item">{name}</li>; } export default function PackingList() { return ( <section> <h1>Спіс рэчаў Салі Райд</h1> <ul> <Item isPacked={true} name="Касмічны скафандр" /> <Item isPacked={true} name="Шлем з залатым лістом" /> <Item isPacked={false} name="Фота Тэма" /> </ul> </section> ); }
Паспрабуйце адрэдагаваць тое, што вяртаецца ў кожным выпадку, і паглядзіце, як зменіцца вынік!
Звярніце ўвагу, як вы ствараеце разгалінаваную логіку з дапамогай JavaScript аператараў if
і return
. У React паток кіравання (напрыклад, умовы) апрацоўваецца JavaScript.
Умоўнае вяртанне нічога, з дапамогай null
У некаторых сітуацыях вам можа спатрэбіцца ўвогуле нічога не рэндэрыць. Напрыклад, вы наогул не хочаце паказваць спакаваныя рэчы. Але кампанент павінен нешта вяртаць. У гэтым выпадку вы можаце вярнуць null
:
if (isPacked) {
return null;
}
return <li className="item">{name}</li>;
Калі isPacked
мае значэнне true
— кампанент нічога не вяртае, null
. У адваротным выпадку ён верне JSX для рэндэрынгу.
function Item({ name, isPacked }) { if (isPacked) { return null; } return <li className="item">{name}</li>; } export default function PackingList() { return ( <section> <h1>Спіс рэчаў Салі Райд</h1> <ul> <Item isPacked={true} name="Касмічны скафандр" /> <Item isPacked={true} name="Шлем з залатым лістом" /> <Item isPacked={false} name="Фота Тэма" /> </ul> </section> ); }
На практыцы вяртанне null
з кампанента не з’яўляецца звычайнай практыкай, таму што гэта можа здзівіць распрацоўшчыка, які спрабуе рэндэрыць яго. Часцей вы будзеце ўмоўна ўключаць або выключаць кампанент у JSX бацькоўскага кампанента. Вось як гэта можна зрабіць!
Умоўнае ўключэнне JSX
У папярэднім прыкладзе вы кантралявалі, якое JSX дрэва будзе вернута кампанентам (калі нешта будзе вернута ўвогуле!). Магчыма, вы ўжо заўважылі нейкае дубліраванне ў вывадзе рэндэрынгу:
<li className="item">{name} ✅</li>
вельмі падобна на
<li className="item">{name}</li>
Абедзве галіны вяртаюць <li className="item">...</li>
:
if (isPacked) {
return <li className="item">{name} ✅</li>;
}
return <li className="item">{name}</li>;
Хоць гэта дубліраванне і не шкоднае, але яно можа ўскладніць падтрыманне вашага кода. Што калі вы захочаце змяніць className
? Вам трэба будзе зрабіць гэта ў двух месцах у вашым кодзе! У такой сітуацыі вы можаце ўмоўна ўключыць невялікі JSX, каб зрабіць свой код больш DRY (сухім).
Умоўны (тэрнарны) аператар (? :
)
JavaScript мае кампактны сінтаксіс для запісу ўмоўнага выражэння — умоўны аператар або «тэрнарны аператар».
Замест гэтага:
if (isPacked) {
return <li className="item">{name} ✅</li>;
}
return <li className="item">{name}</li>;
Вы можаце напісаць гэта:
return (
<li className="item">
{isPacked ? name + ' ✅' : name}
</li>
);
Гэта можна прачытаць як: «Калі ispacked
роўны true
, тады (?
) рэндэрым name + ' ✅'
, інакш (:
) рэндэрым name
».
Deep Dive
Калі вы знаёмы з аб’ектна-арыентаваным праграмаваннем, вы можаце выказаць здагадку, што два прыведзеныя вышэй прыклады крыху адрозніваюцца, таму што адзін з іх можа стварыць два розныя «асобнікі» <li>
. Але JSX элементы не з’яўляюцца «асобнікамі», таму што яны не маюць ніякага ўнутранага стану і не з’яўляюцца сапраўднымі вузламі DOM. Гэта лёгкія апісанні, як чарцяжы. Такім чынам, гэтыя два прыклады, на самай справе, цалкам эквівалентныя. Захаванне і скідванне стану падрабязна распавядае пра тое, як гэта працуе.
Зараз дапусцім, што вы жадаеце абгарнуць завершаны тэкст элемента ў іншы HTML тэг, напрыклад <del>
, каб выкрасліць яго. Вы можаце дадаць новыя радкі і круглыя дужкі, каб было лягчэй укладваць JSX у кожным з выпадкаў:
function Item({ name, isPacked }) { return ( <li className="item"> {isPacked ? ( <del> {name + ' ✅'} </del> ) : ( name )} </li> ); } export default function PackingList() { return ( <section> <h1>Спіс рэчаў Салі Райд</h1> <ul> <Item isPacked={true} name="Касмічны скафандр" /> <Item isPacked={true} name="Шлем з залатым лістом" /> <Item isPacked={false} name="Фота Тэма" /> </ul> </section> ); }
Гэты стыль добра працуе для простых умоў, але выкарыстоўвайце яго ў меру. Калі вашы кампаненты становяцца занадта заблытанымі з-за вялікай колькасці ўкладзенай умоўнай разметкі, падумайце аб вынясенні часткі кода ў даччыныя кампаненты, каб навесці парадак. У React разметка з’яўляецца часткай вашага кода, таму вы можаце выкарыстоўваць такія інструменты, як пераменныя і функцыі, каб упарадкаваць складаныя выразы.
Лагічны аператар І (&&
)
Яшчэ адно скарачэнне, якое часта сустракаецца ў JavaScript — гэта лагічны аператар І (&&
). Унутры кампанентаў React ён часта выкарыстоўваецца, калі вам трэба адрэндэрыць нейкі JSX, калі ўмова роўная true
, або нічога не рэндэрыць інакш. З дапамогай &&
вы можаце ўмоўна рэндэрыць «птушку», толькі калі isPacked
мае значэнне true
:
return (
<li className="item">
{name} {isPacked && '✅'}
</li>
);
Вы можаце чытаць гэта як «калі isPacked
, тады (&&
) рэндэрым «птушку», у адваротным выпадку — нічога не рэндэрым».
Вось яно ў дзеянні:
function Item({ name, isPacked }) { return ( <li className="item"> {name} {isPacked && '✅'} </li> ); } export default function PackingList() { return ( <section> <h1>Спіс рэчаў Салі Райд</h1> <ul> <Item isPacked={true} name="Касмічны скафандр" /> <Item isPacked={true} name="Шлем з залатым лістом" /> <Item isPacked={false} name="Фота Тэма" /> </ul> </section> ); }
JavaScript выраз && вяртае значэнне правага боку (у нашым выпадку «птушка»), калі левы бок (наша ўмова) з’яўляецца true
. Але калі наша ўмова — false
, тады ўвесь выраз становіцца false
. React разглядае false
як «дзірку» ў дрэве JSX, зусім як null
або undefined
, і нічога не рэндэрыць на гэтым месцы.
Умоўнае прысваенне JSX да пераменнай
Калі скарачэнні перашкаджаюць напісанню зразумелага кода, паспрабуйце выкарыстоўваць аператар if
і пераменную. Вы можаце пераназначыць пераменныя, аб’яўленыя з дапамогай let
, таму пачніце з прадастаўлення прадвызначанага змесціва, якое вы хочаце паказаць, напрыклад, name:
let itemContent = name;
Выкарыстоўвайце аператар if
, каб пераназначыць JSX выраз itemContent
, калі isPacked
мае значэнне true
:
if (isPacked) {
itemContent = name + " ✅";
}
Фігурныя дужкі «адчыняюць акенца» ў JavaScript. Устаўце пераменную з дапамогай фігурных дужак у JSX дрэва, якое вяртаецца з кампанента, уклаўшы раней вылічаны выраз унутр JSX:
<li className="item">
{itemContent}
</li>
Гэты стыль найбольш шматслоўны, але і найбольш гнуткі. Вось ён у дзеянні:
function Item({ name, isPacked }) { let itemContent = name; if (isPacked) { itemContent = name + " ✅"; } return ( <li className="item"> {itemContent} </li> ); } export default function PackingList() { return ( <section> <h1>Спіс рэчаў Салі Райд</h1> <ul> <Item isPacked={true} name="Касмічны скафандр" /> <Item isPacked={true} name="Шлем з залатым лістом" /> <Item isPacked={false} name="Фота Тэма" /> </ul> </section> ); }
Як і раней, гэта працуе не толькі для тэксту, але і для адвольнага JSX:
function Item({ name, isPacked }) { let itemContent = name; if (isPacked) { itemContent = ( <del> {name + " ✅"} </del> ); } return ( <li className="item"> {itemContent} </li> ); } export default function PackingList() { return ( <section> <h1>Спіс рэчаў Салі Райд</h1> <ul> <Item isPacked={true} name="Касмічны скафандр" /> <Item isPacked={true} name="Шлем з залатым лістом" /> <Item isPacked={false} name="Фота Тэма" /> </ul> </section> ); }
Калі вы не знаёмыя з JavaScript, то такая разнастайнасць стыляў спачатку можа здацца ашаламляльнай. Аднак іх вывучэнне дапаможа вам чытаць і пісаць любы JavaScript код, а не толькі React кампаненты! Для пачатку абярыце той, які вам больш падабаецца, і пры неабходнасці звярніцеся да гэтага даведніка, калі забудзецеся, як працуюць іншыя.
Recap
- У React вы кіруеце логікай галінавання з дапамогай JavaScript.
- Вы можаце ўмоўна вярнуць JSX выраз з дапамогай аператара
if
. - Вы можаце ўмоўна захаваць JSX у пераменную, а потым уключыць яе ў іншы JSX, выкарыстоўваючы фігурныя дужкі.
- У JSX выраз
{cond ? <A /> : <B />}
азначае «каліcond
, рэндэрыць<A />
, інакш<B />
». - У JSX выраз
{cond && <A />}
азначае «каліcond
, рэндэрыць<A />
, інакш нічога». - Скарачэнні часта выкарыстоўваюцца, але вы не абавязаны выкарыстоўваць іх, калі аддаяце перавагу простаму
if
.
Challenge 1 of 3: Паказаць значок для неспакаваных рэчаў з дапамогай ? :
Выкарыстоўвайце ўмоўны аператар (cond? a : b
), каб паказаць ❌, калі isPacked
не мае значэнне true
.
function Item({ name, isPacked }) { return ( <li className="item"> {name} {isPacked && '✅'} </li> ); } export default function PackingList() { return ( <section> <h1>Спіс рэчаў Салі Райд</h1> <ul> <Item isPacked={true} name="Касмічны скафандр" /> <Item isPacked={true} name="Шлем з залатым лістом" /> <Item isPacked={false} name="Фота Тэма" /> </ul> </section> ); }