JSX — је XML-слично проширење синтаксе JavaScript-а, развијено од стране React тима за декларативно описивање корисничких интерфејса. За разлику од шаблонизатора, JSX се компајлира у обичне позиве JavaScript функција, што даје пуну моћ језика унутар обележавања. Према React, 2024, JSX је подржан у свим модерним React оквирима и библиотекама.
Главне тачке
JSX (JavaScript XML) — синтаксно проширење за JavaScript, први пут представљено у React-у 2013. године. Омогућава програмерима да опишу структуру корисничког интерфејса у декларативном стилу, комбинујући обележавање и логику у једном фајлу.
Пре појаве JSX-а, програмери су користили текстуалне шаблоне (Mustache, Handlebars) или су ручно креирали DOM елементе путем document.createElement. Оба приступа су имала недостатке: текстуални шаблони нису проверени по типовима, а ручно креирање DOM-а је било гломазно и склоно грешкама.
React је изабрао другачији пут — уграђивање обележавања директно у код. Ова одлука је изазвала расправе у заједници, али је временом постала стандард. Данас се JSX користи не само у React-у, већ и у SolidJS, Preact, Qwik, па чак и у Vue-у кроз додатке.
JSX елемент изгледа као HTML ознака, али се уграђује директно у JavaScript. Сваки елемент се транспилира у позив React.createElement са три аргумента: тип елемента, објекат пропсова и дечји елементи. Један коренски елемент — обавезно правило: JSX израз мора да врати један родитељски елемент или фрагмент.
import React from 'react';
// Основни JSX - један коренски елемент
const element = (
<div className="app">
<h1>Hello, World!</h1>
<p>Welcome to React</p>
</div>
);
Када није потребан додатни DOM чвор, користите React.Fragment или кратку синтаксу <></>. Фрагменти не стварају прави DOM елемент, већ само групишу дечје чворове. Ово је посебно корисно у табелама и листама, где би додатни омотач нарушио HTML структуру.
function Columns() {
return (
<>
<td>First</td>
<td>Second</td>
</>
);
}
Било који JavaScript израз се уграђује у JSX кроз витичасте заграде { }. Унутра се могу користити променљиве, позиви функција, тернарни оператори и методе низова. Условно рендеровање се врши кроз тернарни оператор или логичко И.
function Greeting({ name, isLoggedIn }) {
const items = ['Red', 'Green', 'Blue'];
return (
<div>
{/* Expression with variable */}
<h1>Hello, {name}</h1>
{/* Conditional rendering */}
{isLoggedIn ?
<p>Welcome back!</p :
<button>Login</button>
}
{/* Render array */}
<ul>
{items.map(item =>
<li key={item}>{item}</li>
)}
</ul>
</div>
);
}
Кључно ограничење — унутар витичастих заграда могу се користити само изрази, не наредбе. Не могу се користити if/else, for, switch — само тернарни оператор, логички оператори и методе низова. Позиви функција, укључујући стреличасте функције, су дозвољени.
JSX је визуелно сличан HTML-у, али има битне разлике. Атрибути се пишу у camelCase — className уместо class, onClick уместо onclick, tabIndex уместо tabindex. Ово је зато што се JSX транспилира у JavaScript, где цртица у имену својства није дозвољена.
| HTML | JSX | Разлог |
|---|---|---|
class="wrapper" | className="wrapper" | class — резервисана реч у JS-у |
onclick="handle()" | onClick={handle} | camelCase за JS својства |
style="color: red" | style={{ color: 'red' }} | Објекат стилова уместо ниске |
<input disabled> | <input disabled={true}> | Експлицитно навођење булових атрибута |
Још једна важна разлика — самозатварајуће ознаке. У HTML-у неке ознаке (br, hr, input) могу остати незатворене. У JSX-у све самозатварајуће ознаке морају имати затварајућу косу црту: <br />, <input />. Имена SVG атрибута се такође конвертују у camelCase: strokeWidth, fillOpacity.
Прегледачи не разумеју JSX директно. Пре извршавања, JSX код пролази кроз транспилер — Babel, TypeScript или esbuild. Сваки JSX елемент се претвара у позив createElement или jsx/runtime.
// Оригинални JSX
const element = <h1 className="title">Hello</h1>;
// Након транспилације
const element = React.createElement(
'h1',
{ className: 'title' },
'Hello'
);
Од React 17, појавила се нова JSX трансформација која не захтева увоз React-а. Аутоматски увоз jsx-runtime омогућава писање компоненти без import React from 'react'. Babel и TypeScript подржавају ову трансформацију кроз подешавање {"runtime": "automatic"}.
Иако се JSX повезује са React-ом, и други оквири га користе. SolidJS користи JSX са компилацијом у праве DOM чворове, без Virtual DOM-а. Preact — лагана алтернатива React-у са потпуном подршком за JSX. Vue подржава JSX кроз @vue/babel-plugin-jsx, иако му је главни шаблон template.
Кључна разлика — семантика израза. У React-у, JSX изрази се извршавају при сваком рендеровању. У SolidJS-у, JSX се компајлира једном, а ажурирања се прате кроз сигнале. Ово утиче на перформансе: SolidJS не захтева Virtual DOM и реконсилијацију, па је JSX рендеровање брже.
У TypeScript-у, JSX је подржан на нивоу језика. Фајлови са екстензијом .tsx аутоматски обрађују JSX синтаксу. Типизација пропсова — једна од главних предности TypeScript + JSX: IDE сугерише очекиване атрибуте, типове колбекова и обавезност пропсова.
Пишите JSX код који је лако читати и одржавати. Издвајајте сложене изразе у посебне променљиве или функције — ово побољшава читљивост и омогућава тестирање логике одвојено од обележавања. Користите фрагменте уместо непотребних div омотача.
Правило увлачења — поштујте увлачења за угнежђене елементе. Сваки ниво угнежђења — један ниво увлачења. Затварајућа ознака треба да буде на нивоу отварајуће. За дугачке атрибуте користите прелом линије.
Избегавајте стреличасте функције у линији у пропсовима, ако се креирају при сваком рендеровању. У таквим случајевима, умотајте колбек у useCallback или изнесите функцију ван компоненте. Раздвајајте сложене компоненте на мање — свака компонента треба да буде одговорна за једну логичку јединицу интерфејса.
Често постављана питања
Да, кроз Babel додатак @babel/plugin-transform-react-jsx може се подесити JSX за било коју библиотеку. SolidJS, Preact, Nerv и други оквири користе JSX са сопственим runtime-овима. За потпуну независност можете поставити pragma на своју функцију.
class је резервисана реч у JavaScript-у. JSX се транспилира у createElement, где се као други аргумент преноси објекат пропсова. Својство class је у конфликту са класном синтаксом ES6, па је React изабрао className.
Користите шаблонске ниске или библиотеку classnames: className={`“btn ${isActive ? 'active' : ''}”`}. За сложену логику повежите npm пакет clsx или classnames, који прихватају објекте и низове.
JSX подржава само изразе, не наредбе. За услове користите тернарни оператор, логичко И (&&) или логичко ИЛИ (||). За сложену логику издвојите услов у посебну променљиву или функцију.
Атрибут key помаже React-у да идентификује елементе листе при поновном рендеровању. Без key-а, React прецртава целу листу при промени. Са јединственим key-ем, React поново користи DOM чворове и преуређује елементе уместо да их поново ствара.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође