JSX In Depth
Pada dasarnya, JSX hanya menyediakan sintaksis-sintaksis yang mudah ditulis dan dimengerti (syntatic sugar) untuk fungsi React.createElement(component, prop, ...children)
. Kode JSX:
<MyButton color="blue" shadowSize={2}>
Klik saya
</MyButton>
di-compile menjadi:
React.createElement(
MyButton,
{color: 'blue', shadowSize: 2},
'Klik saya'
)
Anda juga dapat menggunakan self-closing form dari tag jika tidak ada turunan (children). Jadinya:
<div className="sidebar" />
di-compile menjadi:
React.createElement(
'div',
{className: 'sidebar'}
)
Jika Anda ingin mencoba bagaimana JSX yang spesifik JSX dikonversi menjadi JavaScript, cobalah undefined ini.
Spesifikasi Jenis Elemen React
Bagian pertama dari sebuah penanda (tag) JSX menentukan jenis dari elemen React.
Jenis-jenis yang dikapitalisasi menandakan bahwa penanda JSX merujuk pada sebuah komponen React. Penanda-penanda ini dikompilasi menjadi sebuah acuan langsung ke variabe yang sudah diberi nama, jadi jika Anda menggunakan ekspresi JSX <Foo />
, Foo
harus berada dalam cakupan (scope).
React Harus Berada dalam Cakupan
Semenjak JSX mengompilasi jadi panggilan-panggilan pada React.createElement
, React
library juga harus selalu berada dalam cakupan dari kode JSX Anda.
Contohnya, kedua import tersebut dibutuhkan dalam kode ini, bahkan ketika React
dan CustomButton
tidak secara langsung mengacu dari JavaScript:
import React from 'react';import CustomButton from './CustomButton';
function WarningButton() {
// return React.createElement(CustomButton, {color: 'red'}, null); return <CustomButton color="red" />;
}
Jika Anda tidak menggunakan sebuah bundler JavaScript dan memuat React dari penanda <script>
, penanda tersebut sudah termasuk di dalam cakupan seperti halnya React
secara global.
Menggunakan Notasi Titik untuk Jenis JSX
Anda juga bisa merujuk pada sebuah komponen React menggunakan notasi titik dari dalam JSX. Ini memudahkan jika Anda memiliki sebuah modul tunggal yang mengekspor bnayak komponen React. Contohnya, jika MyComponents.DatePicker
adalah sebuah komponen, Anda bisa menggunakannya langsung dari JSX dengan cara:
import React from 'react';
const MyComponents = {
DatePicker: function DatePicker(props) {
return <div>Imagine a {props.color} datepicker here.</div>;
}
}
function BlueDatePicker() {
return <MyComponents.DatePicker color="blue" />;}
Komponen User-Defined Harus Dikapitalisasi
Ketika sebuah tipe elemen dimulai dengan sebuah huruf kecil (lowercase), hal tersebut merujuk pada sebuah komponen bawaan seperti <div>
atau <span>
dan menghasilkan sebuah string 'div'
atau 'span'
yang dioper ke React.createElement
. Pengetikan yang dimulai dengan huruf kapital seperti <Foo />
dikompilasi ke React.createElement(Foo)
dan sesuai dengan sebuah komponen yang didefinisikan atau diimpor dalam file JavaScript Anda.
Kami merekomendasikan pemberian nama komponen dengan huruf kapital. Jika Anda memiliki sebuah komponen yang dimulai dengan sebuah huruf lowercase, serahkan komponen tersebut ke variabel yang dikapitalisasi sebelum menggunakannya dalam JSX.
Sebagai contoh, kode ini tidak akan berjalan seperti yang diharapkan:
import React from 'react';
// Salah! Ini adalah sebuah komponen dan seharusnya dikapitalisasi:function hello(props) { // Benar! Penggunaan <div> ini sesuai dengan aturan karena div adalah penanda HTML yang valid:
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
// Salah! React pikir bahwa <hello /> adalah sebuah penanda HTML karena tidak dikapitalisasi: return <hello toWhat="World" />;}
Untuk memperbaiki ini, kita akan menamakan ulang hello
menjadi Hello
dan menggunakan <Hello />
ketika mengacu ke sana:
import React from 'react';
// Benar! Ini adalah sebuah komponen dan memang seharusnya dikapitalisasi:function Hello(props) { // Benar! Penggunaan <div> ini sesuai aturan karena div adalah sebuah penanda HTML yang valid:
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
// Benar! React tahu bahwa <Hello /> adalah sebuah komponen karena dikapitalisasi. return <Hello toWhat="World" />;}
Memilih Jenis yang Tepat pada Runtime
Anda tidak bisa menggunakan sebuah ekspresi umum sebagai jenis elemen React. Jika ingin menggunakan sebuah ekspresi umum untuk mengindikasikan jenis elemen, serahkan saja ekspresi umum tersebut ke variabel yang dikapitalisasi dahulu. Ini seringkali muncul ketika Anda ingin me-render sebuah komponen berbeda berdasarkan sebuah prop:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Salah! Tipe JSX tidak boleh berupa ekspresi. return <components[props.storyType] story={props.story} />;}
Untuk memperbaiki ini, kita akan menyerahkan jenis tersebut ke sebuah variabel yang dikapitalisasi terlebih dahulu:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Benar! Jenis JSX belum berupa sebuah variable yang dikapitalisasi. const SpecificStory = components[props.storyType]; return <SpecificStory story={props.story} />;}
Prop dalam JSX
Terdapat beberapa cara berbeda untuk men-spesifikasikan prop dalam JSX.
JavaScript Expressions as Props
Anda bisa mengoper ekspresi JavaScript sebagai sebuah prop, dengan cara melingkunginya dengan {}
. Contohnya, dalam JSX ini:
<MyComponent foo={1 + 2 + 3 + 4} />
Untuk MyComponent
, nilai props.foo
akan menjadi 10
karena ekspresi 1 + 2 + 3 + 4
telah ditaksi.
Pernyataan-pernyataan if
dan pengulangan-pengulangan (loop) for
bukanlah ekspresi dalam JavaScript, jadi hal-hal tersebut tidak bisa digunakan secara langsung dalam JSX. Sebagai gantinya, Anda bisa menempatkan ini di dalam kode yang melingkupi. Contohnya:
function NumberDescriber(props) {
let description;
if (props.number % 2 == 0) { description = <strong>even</strong>; } else { description = <i>odd</i>; } return <div>{props.number} is an {description} number</div>;
}
Anda bisa mempelajari lebuh lanjut proses render kondisional dan pengulangan di bagian-bagian yang sesuai.
String Literal
Anda dapat mengoper sebuah string literal sebagai sebuah prop. Kedua ekspresi JSX berikut ini sama:
<MyComponent message="hello world" />
<MyComponent message={'hello world'} />
Ketika Anda mengoper sebuah string literal, nilainya tidak luput dari HTML (HTML-unescaped). Jadi kedua eskpresi JSX berikut ini sama:
<MyComponent message="<3" />
<MyComponent message={'<3'} />
Perilaku ini biasanya tidak relevan. Dan hanya disebutkan di sini untuk melengkapi.
Nilai Default Prop adalah “True”
Jika Anda tidak mengoper nilai apapun ke sebuah prop, nilai default-nya adalah ‘true’. Kedua ekspresi JSX ini adalah sama:
<MyTextBox autocomplete />
<MyTextBox autocomplete={true} />
Secara umum, kami tidak merekomendasikan menggunakan cara ini karena bisa membingungkan Anda dengan shorthand objek ES6 {foo}
yang merupakan kependekan dari {foo: foo}
ketimbang {foo: true}
. Perilaku ini demikian adanya karena cocok dengan perilaku HTML.
Menyebarkan Atribut
Jika Anda memiliki props
sebagai sebuah objek, dan ingin mengopernya ke JSX, Anda bisa gunakan ...
sebagai sebuah operator “penyebaran” (spread) untuk mengoper ke objek prop yang utuh. Kedua komponen ini adalah sama:
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;}
Anda juga bisa mengambil prop tertentu yang mana komponen Anda akan gunakan ketika mengoperkan semua prop lainnya menggunakan operator penyebaran.
const Button = props => {
const { kind, ...other } = props; const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
return <button className={className} {...other} />;
};
const App = () => {
return (
<div>
<Button kind="primary" onClick={() => console.log("clicked!")}>
Hello World!
</Button>
</div>
);
};
Pada contoh di atas, prop kind
tersebut secara aman digunakan dan tidak dioper kepada elemen <button>
dalam DOM.
Semua prop lainnya dioper melalui objek ...other
membuat komponen ini begitu fleksibel. Anda bisa lihat bahwa komponen tersebut mengoper sebuah prop onClick
dan prop children
.
Penyebaran atribut bisa berguna tetapi juga membuatnya mudah mengoper prop yang tidak perlu ke komponen-komponen yang tidak memperdulikan prop tersebut atau mengoper atribut-atribut HTML yang tidak valid ke DOM. Kami rekomendasikan menggunakan sintaks ini seperlunya.
Children dalam JSX
Dalam ekspresi JSX yang mengandung penanda (tag) pembuka dan tag penutup, konten yang ada di antara penanda tersebut dioper sebagai prop khusus: props.children
. Ada beberapa cara berbeda untuk mengoper turunan (children):
String Literal
Anda dapat menempatkan sebuah string di antara tag pembuka dan penutup dan props.children
akan menjadi string tersebut. Ini berguna untuk banyak elemen HTML yang built-in. Contohnya:
<MyComponent>Hello world!</MyComponent>
Ini adalah JSX yang valid , dan props.children
dalam MyComponent
secara sederhana akan menjadi string "Hello world!"
. HTML tersebut tidak terhindarkan, jadi Anda secara umum akan menuliskan JSX selayaknya Anda menuliskan HTML dengan cara berikut:
<div>Ini adalah HTML valid & JSX pada waktu yang sama.</div>
JSX mentingkirkan ruang putih (whitespace) di awal dan akhir sebuah baris. JSX juga menyingkirkan baris-baris yang kosong. Baris-baris baru yang berbatasan dengan tag juga disingkirkan; baris-baris baru yang muncul di tengah string literal dipadatkan menjadi sebuah space tunggal. Jadi semua ini akan me-render hasil yang sama:
<div>Hello World</div>
<div>
Hello World
</div>
<div>
Hello
World
</div>
<div>
Hello World
</div>
Turunan (Children) JSX
Anda juga bisa menyediakan lebih banyak elemen JSX sebagai turunan (children). Hal ini berguna untuk menampilkan komponen yang nested:
<MyContainer>
<MyFirstComponent />
<MySecondComponent />
</MyContainer>
Anda juga bisa mencampurkan jenis-jenis turunan yang berbeda, jadi Anda bisa mengguankan string literal bersamaan dengan turunan JSX. Inin adalah cara lain yang mana JSX seperti halnya HTML, jadi hasilnya JSX yang valid dan HTML yang valid:
<div>
Here is a list:
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
Sebuah komponen React juga bisa memberi hasil balikan (return) berupa sebuah array elemen:
render() {
// Tidak perlu untuk membungkus daftar itemd dalam sebuah elemen tambahan!
return [
// Jangan lupa kuncinya :)
<li key="A">Item pertama</li>,
<li key="B">Item kedua</li>,
<li key="C">Item ketiga</li>,
];
}
Ekspresi JavaScript sebagai Children
Anda dapat mengoper ekspresi JavaScript apapun sebagai turunan, dengan cara memenyertakannya di antara {}
. Sebagai contoh, ekspresi-ekspresi ini adalah sama:
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent>
Ini seringkali berguna untuk me-render sebuah daftar ekspresi JSX yang panjangnya dapat berubah-ubah. Contohnya, berikut ini me-render sebuah daftar HTML:
function Item(props) {
return <li>{props.message}</li>;}
function TodoList() {
const todos = ['menyelesaikan doc', 'men-submit pr', 'nag dan untuk di-review'];
return (
<ul>
{todos.map((message) => <Item key={message} message={message} />)} </ul>
);
}
Ekspresi-ekspresi JavaScript juga dapat dicampurkan dengan jenis-jenis turunan lain. Ini seringkali berguna dalam pengganti string template:
function Hello(props) {
return <div>Hello {props.addressee}!</div>;}
Fungsi sebagai Turunan (Children)
Normalnya, ekspresi JavaScript dimasukkan ke dalam JSX akan ditaksir menjadis sebuah string, sebuah elemen React, atau menjadi daftar hal-hal semacam itu. Bagaimanapun, props.children
bekerja seperti halnya prop apapun yang mana bisa mengoper jenis data apapun, tidak hanya jenis data yang React tahu bagaimana cara untuk me-render-nya. Contohnya, jika Anda memiliki sebuah komponen custom, Anda bisa melakukan callback pada komponen tersebut sebagai props.children
:
// Memanggil callback turunan numTimes untuk menghasilkan sebuah komponen berulang
function Repeat(props) {
let items = [];
for (let i = 0; i < props.numTimes; i++) { items.push(props.children(i));
}
return <div>{items}</div>;
}
function ListOfTenThings() {
return (
<Repeat numTimes={10}>
{(index) => <div key={index}>This is item {index} in the list</div>} </Repeat>
);
}
Turunan dioper ke sebuah komponen custom bisa berarti apa saja, selama komponen itu mengubah turunan-turunan tersbut menjadi sesuatu yang bisa dimengerti React sebelum proses render. Penggunaan ini tidak lazim, namun berkerja jika Anda ingin melebarkan apa saja yang dapat dilakukan JSX.
Boolean, Null, dan Undefined Diabaikan
false
, null
, undefined
, dan true
adalah turunan yang valid. Itu semua tidak di-render. Ekspresi-ekspresi JSX akan me-render hasil yang sama:
<div />
<div></div>
<div>{false}</div>
<div>{null}</div>
<div>{undefined}</div>
<div>{true}</div>
Ini berguna untuk secara kondisional me-render elemen-elemen React. JSX ini me-render komponen <Header />
hanya jika showHeader
bernilai true
:
<div>
{showHeader && <Header />} <Content />
</div>
Satu peringatan bahwa beberapa nilai “salah”, seperti angka 0
, masih di-render oleh React. Contohnya, kode berikut ini tidak akan berlaku seperi yang Anda kira karena 0
akan dicetak ketika props.messages
adalah array kosong:
<div>
{props.messages.length &&
<MessageList messages={props.messages} />
}
</div>
Untuk memperbaiki ini, pastikan bahwa ekspresi sebelum &&
adalah boolean:
<div>
{props.messages.length > 0 && <MessageList messages={props.messages} />
}
</div>
Sebaliknya, jika Anda ingin sebuah nilai seperti false
, true
, null
, atau undefined
untuk muncul di output, Anda harus mengkonversinya menjadi sebuah string terlebih dahulu:
<div>
My JavaScript variable is {String(myVariable)}.</div>