Tutorial: Pengantar React
Tutorial ini tidak membutuhkan pengetahuan tentang React sebelumnya.
Sebelum Kita Memulai Tutorial
Kita akan membangun sebuah gim kecil sepanjang tutorial ini. Anda bisa jadi tergoda untuk melewati tutorial ini karena Anda tidak benar-benar membuat gim — namun luangkanlah sedikit waktu untuk mencobanya. Teknik-teknik yang akan Anda pelajari pada tutorial ini adalah hal-hal dasar yang digunakan untuk membangun aplikasi React, dan menguasai teknik-teknik tersebut akan memberikan pemahaman terhadap React secara lebih mendalam.
Tips
Tutorial ini didesain untuk orang yang lebih suka belajar dengan mempraktikkan. Jika Anda lebih suka mempelajari konsep dari tingkat dasar sampai tingkat lanjut, lihat panduan langkah demi langkah kami. Anda akan menyadari bahwa tutorial dan panduan akan saling melengkapi.
Tutorial ini akan dibagi menjadi beberapa bagian:
- Mempersiapkan Tutorial merupakan titik awal Anda untuk mengikuti tutorial.
- Ikhtisar bagian ini berisi hal-hal mendasar React: komponen, props, dan state.
- Menyelesaikan Permainan bagian ini berisi teknik-teknik yang paling umum pada pengembangan aplikasi React.
- Menambahkan Penjelajahan Waktu bagian ini akan memberikan pemahaman yang lebih mendalam pada kekuatan unik dari React.
Anda tidak perlu menyelesaikan semua bagian sekaligus untuk mendapatkan pembelajaran dari tutorial ini. Cobalah mengerjakan semampu Anda — walaupun hanya satu atau dua bagian.
Apa yang Kita Kembangkan?
Dalam tutorial ini, kami akan menunjukkan cara membuat permainan tic-tac-toe interaktif menggunakan React.
Anda dapat melihat gambaran aplikasi yang akan kita buat di sini: Hasil Akhir. Jika kode tersebut tidak masuk akal untuk Anda, atau Anda tidak akrab dengan sintaks kode tersebut, jangan khawatir! Tujuan dari tutorial ini adalah untuk membantu Anda mengerti React dan sintaksnya.
Kami merekomendasikan Anda untuk mencari tahu tentang permainan tic-tac-toe sebelum melanjutkan tutorial ini. Salah satu fitur yang akan Anda lihat adalah adanya daftar bernomor di sebelah kanan papan permainan. Daftar ini memberikan Anda semua riwayat langkah yang sudah terjadi dalam permainan, dan terus diperbarui selama permainan berlangsung.
Anda bisa menutup laman permainan tic-tac-toe setelah Anda paham dengan permainan tersebut. Kita akan memulai dari templat sederhana pada tutorial ini. Langkah selanjutnya adalah mempersiapkan Anda sehingga Anda dapat memulai mengembangkan permainan tic-tac-toe.
Prasyarat
Kami mengasumsikan bahwa Anda memiliki pemahaman akan HTML dan JavaScript, namun Anda seharusnya tetap dapat mengikuti tutorial ini jika Anda memiliki pemahaman pada bahasa pemrograman lainnya. Kami juga berasumsi bahwa Anda memiliki pemahaman akan konsep pemrograman seperti fungsi, objek, senarai, dan pada tingkat yang lebih rendah, kelas.
Jika Anda memerlukan pengingat tentang JavaScript, kami merekomendasikan Anda untuk membaca panduan ini. Perlu diperhatikan juga bahwa kita menggunakan beberapa fitur dari ES6 — versi terbaru JavaScript. Di tutorial ini, kita menggunakan statement arrow functions, kelas, let
, dan const
. Anda dapat menggunakan Babel REPL untuk melihat hasil kompilasi kode ES6.
Mempersiapkan Tutorial
Ada dua cara untuk menyelesaikan tutorial ini: Anda dapat menulis kode pada browser Anda atau mempersiapkan local development environment pada komputer Anda.
Persiapan Cara 1: Menulis Kode pada Browser
Ini adalah cara tercepat untuk memulai!
Pertama, buka kode permulaan ini pada tab baru. Tab baru tersebut seharusnya menunjukan papan permainan tic-tac-toe yang kosong dan kode React. Kita akan mengedit kode React tersebut pada tutorial ini.
Anda dapat melewati cara kedua untuk persiapan dan menuju ke bagian Ikhtisar untuk mendapatkan ikhtisar dari React.
Persiapan Cara 2: Local Development Environment
Cara ini murni opsional dan tidak wajib pada tutorial ini!
Opsional: Instruksi untuk mengikuti secara lokal menggunakan editor teks pilihan Anda
Persiapan ini membutuhkan lebih banyak langkah tetapi membuat Anda dapat menyelesaikan tutorial ini menggunakan editor teks pilihan Anda. Berikut adalah beberapa langkah yang harus diikuti:
- Pastikan Anda sudah meng-install Node.js versi terbaru.
- Ikuti langkah instalasi Create React App untuk membuat project baru.
npx create-react-app my-app
- Hapus semua file pada folder
src/
dari project baru Anda.
Catatan: jangan hapus seluruh folder
src
, cukup file-file yang ada di dalamnya saja. Kita akan menggantikan file-file tersebut dengan contoh-contoh yang akan diberikan melalui tutorial ini.
cd my-app
cd src
# Jika Anda menggunakan Mac atau Linux:
rm -f *
# Atau jika Anda menggunakan Windows:
del *
# Kemudian, kembali ke folder project
cd ..
- Tambahkan file bernama
index.css
ke dalam foldersrc/
dengan kode CSS ini. - Tambahkan file bernama
index.js
ke dalam foldersrc/
dengan kode JS ini. - Tambahkan tiga baris kode berikut pada bagian paling atas
index.js
di dalam foldersrc/
:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
Sekarang, jika Anda menjalankan npm start
pada folder project Anda dan mengakses http://localhost:3000
pada browser Anda, Anda akan melihat papan tic-tac-toe yang kosong.
Kami merekomendasikan Anda untuk mengikuti instruksi ini untuk mengkonfigurasi syntax highlighting untuk editor Anda.
Tolong, Saya Mengalami Masalah!
Jika Anda mengalami masalah, silahkan kunjungi sumber dukungan komunitas. Secara khusus, Reactiflux Chat adalah langkah yang baik untuk mendapat bantuan dengan cepat. Jika Anda tidak mendapat jawaban, atau tetap mengalami masalah, maka silahkan mengajukan issue, dan kami akan membantu Anda.
Ikhtisar
Sekarang karena Anda sudah siap, mari mempelajari ikhtisar dari React!
Apa Itu React?
React adalah library JavaScript yang deklaratif, efisien, dan fleksibel untuk membangun antarmuka pengguna. React memungkinkan Anda untuk membuat antarmuka kompleks dari kumpulan kode yang kecil dan terisolasi yang disebut “komponen”.
React memiliki beberapa jenis komponen, tetapi kita akan memulai dengan subkelas React.Component
:
class ShoppingList extends React.Component {
render() {
return (
<div className="shopping-list">
<h1>Daftar Belanja untuk {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}
// Contoh Penggunaan: <ShoppingList name="Mark" />
Kita akan membahas tag aneh yang seperti XML sesaat lagi. Kita menggunakan komponen untuk memberi tahu React yang ingin kita lihat pada layar. Ketika data kita berubah, React akan memperbarui dan me-render ulang komponen kita dengan efisien.
Di sini, ShoppingList adalah kelas komponen React atau tipe komponen React. Sebuah komponen dapat menerima parameter yang disebut dengan props
(singkatan dari properties
) dan mengembalikan sebuah hirarki dari tampilan-tampilan yang akan ditampilkan via method render
.
Method render
mengembalikan sebuah deskripsi dari benda yang akan Anda lihat pada layar. React mengambil deskripsi tersebut dan menampilkan hasilnya ke layar. Secara khusus, render
mengembalikan elemen React, yang merupakan deskripsi ringan tentang yang harus di-render
. Kebanyakan pengembang React menggunakan sintaks khusus yang disebut “JSX” yang memudahkan struktur dari React mudah untuk ditulis. Sintaks <div />
akan diubah menjadi React.createElement('div')
pada saat build. Contoh di atas sama dengan sintaks berikut:
return React.createElement('div', {className: 'shopping-list'},
React.createElement('h1', /* ... h1 children ... */),
React.createElement('ul', /* ... ul children ... */)
);
Jika Anda penasaran, createElement()
dideskripsikan dengan lebih rinci pada bagian referensi API, tetapi kita tidak akan menggunakannya pada tutorial ini. Kita akan tetap menggunakan JSX.
JSX hadir dengan kekuatan penuh dari JavaScript. Anda dapat menulis setiap ekspresi JavaScript di antara tanda kurung kurawal di dalam JSX. Setiap elemen React adalah objek JavaScript yang dapat Anda simpan di dalam variabel atau Anda oper ke seputar program Anda.
Komponen ShoppingList
di atas hanya me-render komponen DOM built-in seperti <div />
dan <li />
. Namun, Anda juga dapat membuat dan me-render komponen React Anda sendiri. Contohnya, kita dapat mengacu ke seluruh daftar belanja di atas dengan menuliskan <ShoppingList />
. Setiap komponen React terenkapsulasi dan dapat beroperasi secara mandiri; hal ini memungkinkan Anda untuk membangun sebuah antarmuka pengguna yang kompleks dari komponen sederhana.
Melihat Kode Permulaan
Jika Anda akan mengikuti tutorial ini di browser Anda, buka kode ini pada tab baru: Kode Permulaan. Jika Anda mengikuti tutorial ini dengan local environment Anda, bukalah src/index.js
pada folder project Anda (Anda sudah pernah menyentuh file ini selama persiapan).
Kode Permulaan ini berdasarkan pada aplikasi yang akan kita buat. Kami sudah menyediakan style CSS sehingga Anda bisa fokus mempelajari React dan memprogram permainan tic-tac-toe.
Dengan melihat kode permulaan, Anda akan melihat bahwa kita memiliki tiga komponen React:
- Square
- Board
- Game
Komponen Square akan me-render sebuah <button>
dan komponen Board akan me-render 9 persegi. Komponen Game akan me-render sebuah papan dengan nilai sementara yang akan kita ganti nanti. Saat ini belum ada komponen interaktif.
Mengoper Data Melalui Props
Untuk memulai mendalami React, mari kita mencoba untuk mengoper data dari komponen Board ke komponen Square kita.
Kami menyarankan mengetik kode-kode berikut secara manual selama Anda mengikuti tutorial ini dan menghindari menggunakan copy/paste. Ini akan membantu mengembangkan memori otot Anda dan meningkatkan pemahaman Anda mengenai React.
Di dalam method renderSquare
Board, ubah kodenya untuk mengoperkan prop bernama value
ke Square:
class Board extends React.Component {
renderSquare(i) {
return <Square value={i} />; }
}
Ubah method render
Square untuk menampilkan nilai tersebut dengan mengganti {/* TODO */}
dengan {this.props.value}
:
class Square extends React.Component {
render() {
return (
<button className="square">
{this.props.value} </button>
);
}
}
Sebelum:
Sesudah: Anda seharusnya melihat angka dari setiap persegi pada keluaran yang telah di-render.
Lihat kode lengkap sampai tahap ini
Selamat! Anda baru saja “mengoperkan sebuah prop” dari komponen Board ke komponen Square. Mengoperkan props adalah cara informasi dapat mengalir dalam aplikasi React dari (komponen) induk ke anak.
Membuat Komponen Interaktif
Mari mengisi komponen Square dengan sebuah “X” ketika kita mengklik komponen tersebut.
Pertama, ubah button tag yang dikembalikan dari fungsi render()
komponen Square menjadi:
class Square extends React.Component {
render() {
return (
<button className="square" onClick={function() { alert('click'); }}> {this.props.value}
</button>
);
}
}
Jika kita mengklik salah satu Square, kita akan mendapatkan alert pada browser kita.
Catatan
Untuk mempercepat proses mengetik dan menghindari perilaku membingungkan
this
, kita akan menggunakan sintaks arrow function untuk setiap event handler yang akan kita buat:class Square extends React.Component { render() { return ( <button className="square" onClick={() => alert('click')}> {this.props.value} </button> ); } }
Perhatikan bahwa dengan
onClick={() => alert('click')}
, kita mengoperkan sebuah fungsi sebagai proponClick
. Fungsi tersebut hanya dieksekusi setelah klik. Lupa untuk menulis() =>
dan menulisonClick={alert('click')}
adalah kesalahan yang sering terjadi, dan menyebabkan fungsi akan terus dijalankan setiap komponen di-render ulang.
Selanjutnya, kita ingin agar komponen Square “mengingat” bahwa komponen tersebut sudah diklik dan mengisinya dengan “X”. Untuk “mengingat” sesuatu, komponen menggunakan state.
Komponen React dapat memiliki state dengan mengatur this.state
pada konstruktornya. this.state
harus dianggap private oleh komponen React tempat ia didefinisikan. Mari menyimpan nilai Square saat ini pada this.state
dan mengubahnya ketika Square diklik.
Pertama, kita akan menambahkan konstruktor pada kelas untuk menginisialisasi state:
class Square extends React.Component {
constructor(props) { super(props); this.state = { value: null, }; }
render() {
return (
<button className="square" onClick={() => alert('click')}>
{this.props.value}
</button>
);
}
}
Catatan
Pada kelas JavaScript, Anda harus selalu memanggil
super
ketika mendefinisikan konstruktor dari sebuah subkelas. Semua kelas komponen React yang memilikiconstructor
harus dimulai dengansuper(props)
.
Sekarang kita akan mengubah method render
Square untuk menampilkan nilai state saat ini ketika diklik:
- Mengganti
this.props.value
denganthis.state.value
di dalam<button>
tag. - Mengganti event handler
onClick={...}
denganonClick={() => this.setState({value: 'X'})}
. - Pisahkan props
className
danonClick
pada baris yang berbeda agar lebih mudah dibaca.
Setelah perubahan di atas, tag <button>
yang dikembalikan dari method render
Square akan terlihat seperti ini:
class Square extends React.Component {
constructor(props) {
super(props);
this.state = {
value: null,
};
}
render() {
return (
<button
className="square" onClick={() => this.setState({value: 'X'})} >
{this.state.value} </button>
);
}
}
Dengan memanggil this.setState
dari handler onClick
pada method render
Square, kita memberi tahu React untuk me-render ulang Square setiap <button>
diklik. Setelah diperbarui, this.state.value
dari Square akan menjadi 'X'
, jadi kita akan melihat X
pada papan permainan. Jika Anda mengklik salah satu Square, maka akan muncul X
.
Ketika Anda memanggil setState
di sebuah component, React akan memperbarui komponen anak di dalamnya secara otomatis.
Lihat kode lengkap sampai tahap ini
Developer Tools
Ekstensi React Devtools untuk Chrome dan Firefox memungkinkan Anda untuk melihat pohon komponen dari React dengan menggunakan perangkat pengembang browser Anda.
React Devtools memungkinkan Anda untuk mengecek props dan state dari komponen React Anda.
Setelah meng-install React Devtools, Anda dapat mengklik kanan elemen manapun pada halaman Anda, kemudian klik “Inspect” untuk membuka perangkat pengembang dan tab React (“⚛️ Components” and “⚛️ Profiler”) akan muncul sebagai tab terakhir di sebalah kanan. Gunakan “⚛️ Components” untuk menginspeksi pohon komponen.
Walaupun demikian, perlu diperhatikan bahwa ada beberapa langkah tambahan untuk membuat aplikasi Anda bekerja dengan CodePen:
- Masuk atau daftar dan konfirmasi email Anda (diperlukan untuk mencegah spam)
- Klik tombol “Fork”.
- Klik “Change View” dan pilih “Debug mode”.
- Pada tab baru yang terbuka, devtools saat ini seharusnya memiliki tab React.
Menyelesaikan Permainan
Sekarang kita sudah memiliki blok-blok dasar untuk membangun permainan tic-tac-toe. Untuk menyelesaikan permainan ini, kita memerlukan penempatan alternatif “X” dan “O” pada papan dan kita memerlukan cara untuk menentukan pemenangnya.
Menaikkan State
Saat ini, setiap komponen Square mengurus state dari permainan. Untuk menentukan pemenang, kita akan mengurus nilai dari setiap persegi di satu lokasi.
Kita dapat memikirkan Board seharusnya cukup mengambil state setiap Square. Walaupun pendekatan ini mungkin di React, tetapi kami tidak menyarankannya karena kodenya akan sulit untuk dimengerti, rentan terhadap bugs, dan sulit untuk di-refactor. Sebagai gantinya, pendekatan terbaik untuk adalah untuk menyimpan state dari permainan pada komponen Board. Komponen Board dapat memberitahu setiap Square untuk menampilkan data dengan memberikannya melalui prop seperti yang kita lakukan saat kita memberikan angka ke setiap Square.
Untuk mengambil data dari beberapa anak atau membuat dua komponen anak berkomunikasi satu sama lain, Anda perlu mendeklarasikan state pada komponen induk. Komponen induk dapat memberikan state ke anak dengan menggunakan props; pola ini dapat membuat komponen-komponen anak tetap sinkron satu sama lain dan dengan komponen induk.
Menaikkan state ke komponen induk lazim ketika me-refactor komponen React. Mari memanfaatkan kesempatan ini untuk mencobanya.
Kita akan menambahkan konstruktor ke Board dan menginisialisasi state dari Board berisi array dengan 9 null. Sembilan nilai ini melambangkan 9 persegi:
class Board extends React.Component {
constructor(props) { super(props); this.state = { squares: Array(9).fill(null), }; }
renderSquare(i) {
return <Square value={i} />;
}
Ketika kita mengisi papan permainan nanti, senarai this.state.squares
akan terlihat seperti ini:
[
'O', null, 'X',
'X', 'X', 'O',
'O', null, null,
]
Method renderSquare
dari Board saat ini terlihat seperti ini:
renderSquare(i) {
return <Square value={i} />;
}
Awalnya, kita mengoperkan prop value dari Board untuk menampilkan angka 0 sampai 8 di setiap Square. Pada langkah berbeda sebelumnya, kita menggantikan angka dengan “X” yang ditentukan oleh state dari Square itu sendiri. Ini sebabnya Square saat ini mengabaikan prop value
yang diberikan oleh Board.
Sekarang kita akan menggunakan mekanisme pengoperan prop lagi. Kita akan memodifikasi Board untuk memberi instruksi pada setiap Square untuk mengubah nilai saat ini ('X'
, 'O'
, atau null
). Kita sudah mendefinisikan senarai squares
pada konstruktor Board dan kita akan memodifikasi method renderSquare
Board untuk membaca dari state:
renderSquare(i) {
return <Square value={this.state.squares[i]} />; }
Lihat kode lengkap sampai tahap ini
Setiap Square akan menerima prop value
yang dapat berupa 'X'
, 'O'
, atau null
untuk persegi kosong.
Selanjutnya, kita perlu mengubah perilaku Square saat diklik. Komponen Board saat ini mengatur persegi yang sedang diisi. Kita perlu memikirkan sebuah cara agar Square dapat memperbarui state di Board. Karena state dianggap sebagai private di dalam suatu komponen, kita tidak dapat mengubah state Board melalui Square secara langsung.
Untuk mempertahankan state privacy dari Board, kita akan memberikan sebuah fungsi dari Board ke Square. Fungsi ini akan dipanggil ketika komponen Square diklik. Kita akan mengubah method renderSquare
di dalam Board menjadi:
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(i)} />
);
}
Catatan
Kita membagi elemen yang dikembalikan menjadi beberapa baris agar lebih mudah dibaca. Kami juga menambahkan tanda kurung sehingga JavaScript tidak menyisipkan titik koma setelah
return
dan merusak kode kita.
Sekarang kita memberikan dua prop dari Board ke Square: value
dan onClick
. Prop onClick
adalah sebuah fungsi yang dapat dipanggil oleh Square ketika diklik. Kita akan membuat perubahan berikut pada Square:
- Mengganti
this.state.value
denganthis.props.value
pada methodrender
Square. - Mengganti
this.setState()
denganthis.props.onClick()
pada methodrender
Square. - Menghapus
constructor
Square karena Square sudah tidak menyimpan state dari permainan.
Setelah perubahan tersebut, komponen Square akan terlihat seperti ini:
class Square extends React.Component { render() { return (
<button
className="square"
onClick={() => this.props.onClick()} >
{this.props.value} </button>
);
}
}
Ketika sebuah Square diklik, fungsi onClick
yang disediakan oleh Board akan dipanggil. Berikut adalah ulasan bagaimana kita dapat memperoleh hasil saat ini:
- Prop
onClick
pada komponen built-in DOM<button>
memberi tahu React untuk menyiapkan event listener klik. - Ketika tombol diklik, React akan memanggil event handler
onClick
yang sudah didefinisikan pada methodrender()
Square. - Event handler ini memanggil
this.props.onClick()
. ProponClick
dari Square ditentukan oleh Board. - Karena Board mengoperkan
onClick={() => this.handleClick(i)}
ke Square, Square memanggilthis.handleClick(i)
ketika diklik. - Kita belum mendefinisikan method
handleClick()
, sehingga kode kita akan crash. Ketika Anda mengeklik sebuah persegi, Anda akan melihat teks error berwarna merah yang bertuliskan semacam “this.handleClick is not a function”.
Catatan
Atribut
onClick
pada elemen DOM<button>
memiliki arti khusus untuk React karena merupakan komponen built-in. Untuk komponen komponen custom seperti Square, penamaan bersifat bebas. Kita dapat menamakan proponClick
Square atauhandleClick
Board dengan nama lain. Namun demikian, dalam React, hal ini adalah sebuah konvensi untuk menggunakan penamaanon[Event]
pada props yang merepresentasikan event danhandle[Event]
untuk method yang menangani event tersebut.
Ketika kita mencoba untuk mengklik salah satu Square, kita seharusnya akan mendapatkan sebuah pesan error karena kita belum mendefinisikan handleClick
. Sekarang kita akan menambahkan handleClick
pada kelas Board:
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
};
}
handleClick(i) { const squares = this.state.squares.slice(); squares[i] = 'X'; this.setState({squares: squares}); }
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>
);
}
render() {
const status = 'Next player: X';
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
}
Lihat kode lengkap sampai tahap ini
Setelah perubahan ini, kita dapat mengklik Square kembali untuk mengisinya. Tetapi, sekarang state disimpan pada komponen Board, bukan pada setiap komponen Square. Ketika state Board berubah, komponen Square akan di-render ulang secara otomatis. Dengan menyimpan state dari setiap persegi pada komponen Board, kita dapat menentukan pemenangnya pada tahap berikutnya.
Karena komponen Square tidak lagi mengatur state, komponen Square menerima nilai dari komponen Board dan memberikan informasi ke komponen Board ketika diklik. Dalam istilah React, komponen Square sekarang disebut dengan controlled components. Komponen Board memiliki kontrol penuh pada komponen Square.
Perhatikan bahwa di dalam handleClick
, kita memanggil .slice()
untuk membuat kopi senarai squares
untuk memodifikasinya sebagai ganti dari memodifikasi senarai yang ada. Kami akan menjelaskan alasan kita membuat kopi dari senarai squares
di bagian selanjutnya.
Mengapa Immutablility Itu Penting
Pada contoh kode sebelumnya, kami menyarankan Anda untuk menggunakan .slice()
untuk membuat kopi dari senarai squares
untuk memodifikasinya sebagai ganti dari memodifikasi senarai yang ada. Kita akan membahas immutability dan mengapa immutability penting untuk dipelajari.
Secara umum, ada dua pendekatan untuk mengubah data. Pendekatan pertama adalah untuk me-mutate data dengan mengubah nilai dari data secara langsung. Pendekatan kedua adalah dengan mengganti data dengan kopi baru yang memiliki perubahan yang diinginkan.
Perubahan Data dengan Mutation
var player = {score: 1, name: 'Jeff'};
player.score = 2;
// Sekarang player adalah {score: 2, name: 'Jeff'}
Perubahan Data Tanpa Mutation
var player = {score: 1, name: 'Jeff'};
var newPlayer = Object.assign({}, player, {score: 2});
// Sekarang player tidak berubah, tetapi newPlayer adalah {score: 2, name: 'Jeff'}
// Atau jika Anda menggunakan sintaks object spread, Anda dapat menuliskan:
// var newPlayer = {...player, score: 2};
Hasil akhir dari kedua pendekatan sama tetapi dengan tidak melakukan mutate (atau mengganti data di dalamnya) secara langsung, kita mendapatkan keuntungan sebagai berikut.
Fitur Kompleks Menjadi Lebih Sederhana
Immutability membuat fitur kompleks menjadi lebih mudah untuk diimplementasikan. Nanti pada tutorial ini juga, kita akan mengimplementasikan fitur “penjelajahan waktu” yang memungkinkan kita untuk mengulas riwayat permainan tic-tac-toe kita dan “lompat kembali” ke langkah sebelumnya. Fungsionalitas ini tidak spesifik ke permainan — sebuah kemampuan untuk undo dan redo beberapa aksi adalah kebutuhan yang umum dalam sebuah aplikasi. Menghindari mutasi data memungkinkan kita untuk menyimpan riwayat permainan sebelumnya utuh dan menggunakannya kembali kemudian.
Mendeteksi Perubahan
Mendeteksi perubahan pada objek mutable sulit karena mereka dimodifikasi secara langsung. Deteksi ini membutuhkan objek mutable tersebut dibandingkan dengan beberapa kopi sebelumnya dari dirinya dan seluruh melintasi seluruh pohon objek.
Mendeteksi perubahan pada objek immutable dianggap lebih mudah. Jika objek immutable yang ditunjuk berbeda dengan objek sebelumnya, maka objeknya sudah berubah.
Menentukan Waktu Untuk Melakukan Render Ulang di React
Keuntungan utama dari immutability adalah membantu Anda untuk membuat pure component di React. Data yang immutable dapat dengan mudah memastikan apakah perubahan sudah terjadi, yang juga membantu untuk menentukan apakah komponen perlu di-render ulang.
Anda dapat mempelajari shouldComponentUpdate()
lebih lanjut dan bagaimana cara membuat pure components dengan membaca Optimisasi Performa.
Function Components
Sekarang kita akan mengubah Square menjadi function component.
Dalam React, function component adalah cara lebih mudah untuk menulis komponen yang hanya berisi method render
dan tidak memiliki state. Sebagai ganti menulis kelas yang merupakan turunan dari React.Component
, kita dapat menulis sebuah fungsi yang menerima props
sebagai masukan dan mengembalikan apa yang harus di-render. Menulis function component lebih tidak jemu dibanding menulis kelas dan banyak komponen dapat ditulis dengan cara ini.
Ganti kelas Square dengan fungsi berikut:
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
Kita sudah mengganti this.props
dengan props
saat muncul.
Lihat kode lengkap sampai saat ini
Catatan
Ketika mengubah Square menjadi function component, kita juga mengubah
onClick={() => this.props.onClick()}
menjadi lebih pendekonClick={props.onClick}
(perhatikan hilangnya tanda kurung pada kedua sisi). Pada kelas, kita menggunakan arrow function untuk mengakses nilaithis
yang benar, tetapi di function component kita tidak perlu mengkhawatirkanthis
.
Mengambil Giliran
Sekarang kita perlu memperbaiki kerusakan yang cukup jelas pada permainan tic-tac-toe kita: “O” tidak dapat dituliskan ke dalam papan.
Kita akan menentukan “X” mengambil giliran pertama sebagai nilai default. Kita dapat menentukan nilai default dengan mengubah state awal pada konstruktor Board:
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
xIsNext: true, };
}
Setiap pemain selesai dengan langkahnya, xIsNext
(sebuah boolean) akan diubah nilainya untuk menentukan siapa yang akan membuat langkah selanjutnya dan state dari permainan akan disimpan. Kita akan mengubah fungsi handleClick
dari Board untuk mengubah nilai dari xIsNext
:
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = this.state.xIsNext ? 'X' : 'O'; this.setState({
squares: squares,
xIsNext: !this.state.xIsNext, });
}
Dengan perubahan ini, “X” dan “O” akan mendapatkan giliran setiap satu langkah selesai.
Mari mengubah teks “status” pada render
di Board, sehingga teks menampilkan pemain mana yang sedang mendapat giliran selanjutnya:
render() {
const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
return (
// sisanya tidak berubah
Setelah mengubahnya, Anda akan memiliki komponen Board berikut:
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
xIsNext: true, };
}
handleClick(i) {
const squares = this.state.squares.slice(); squares[i] = this.state.xIsNext ? 'X' : 'O'; this.setState({ squares: squares, xIsNext: !this.state.xIsNext, }); }
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>
);
}
render() {
const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
}
Lihat kode lengkap sampai tahap ini
Menentukan Pemenang
Sekarang kita sudah menampilkan pemain mana yang akan mendapat giliran selanjutnya, kita juga perlu menampilkan sesuatu ketika permainan sudah dimenangkan oleh salah satu pemain dan tidak ada giliran lagi. Kita dapat menentukan pemenang dengan menambahkan fungsi berikut pada akhir file:
function calculateWinner(squares) {
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
return squares[a];
}
}
return null;
}
Ketika diberi senarai dari kesembilan persegi, fungsi ini akan mengecek pemenang dan 'X'
, 'O'
, atau null
sesuai dengan hasil.
Kita akan memanggil caluclateWinner(squares)
pada fungsi render
Board untuk mengecek adanya salah satu pemain yang sudah menang. Jika salah satu pemain sudah menang, kita dapat menampilkan teks seperti “Winner: X” atau “Winner: O”. Kita akan mengganti deklarasi status
pada fungsi render
Board dengan kode berikut:
render() {
const winner = calculateWinner(this.state.squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); }
return (
// sisanya tidak berubah
Kita dapat mengubah fungsi handleClick
Board untuk kembali lebih awal dengan mengabaikan klik jika salah satu pemain sudah menang atau jika sebuah Square sudah diisi:
handleClick(i) {
const squares = this.state.squares.slice();
if (calculateWinner(squares) || squares[i]) { return; } squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}
Lihat kode lengkap sampai tahap ini
Selamat! Anda sekarang sudah memiliki permainan tic-tac-toe yang berjalan dengan baik. Anda juga telah belajar dasar-dasar dari React. Jadi Anda mungkin adalah pemenang yang sebenarnya disini.
Menambahkan Penjelajahan Waktu
Sebagai latihan terakhir, mari kita membuat permainan kita dapat “kembali” ke langkah sebelumnya pada permainan.
Menyimpan Riwayat Langkah
Jika kita melakukan mutate pada senarai squares
, mengimplementasikan penjelajahan waktu akan sangat sulit.
Tetapi, kita menggunakan slice()
untuk membuat kopi baru dari senarai squares
setelah setiap langkah dan memperlakukannya sebagai immutable. Hal ini akan membuat kita dapat menyimpan setiap versi sebelumnya dari senarai squares
dan melakukan navigasi di antara giliran-giliran yang sudah terjadi.
Kita akan menyimpan riwayat senarai squares
pada senarai lain yang bernama history
. Senarai history
menggambarkan semua state dari Board dari awal hingga akhir, dan memiliki bentuk seperti ini:
history = [
// Before first move
{
squares: [
null, null, null,
null, null, null,
null, null, null,
]
},
// After first move
{
squares: [
null, null, null,
null, 'X', null,
null, null, null,
]
},
// After second move
{
squares: [
null, null, null,
null, 'X', null,
null, null, 'O',
]
},
// ...
]
Sekarang kita akan menentukan komponen yang akan memiliki state history
.
Menaikkan State, Lagi
Kita ingin komponen Game teratas untuk menampilkan riwayat langkah. Untuk melakukan hal tersebut, komponen Game memerlukan akses ke history
, sehingga kita akan menempatkan state history
pada komponen teratas Game.
Menempatkan state history
ke komponen Game memungkinkan kita menghapus state squares
dari komponen anaknya, komponen Board. Seperti yang kita lakukan pada bagian “menaikan state” dari komponen Square ke komponen Board, sekarang kita akan menaikkannya dari Board ke komponen teratas Game. Hal ini memberikan komponen Game kontrol penuh pada data Board dan memungkinkannya untuk memberi instruksi ke Board untuk me-render giliran sebelumnya dari history
.
Pertama, mari kita mempersiapkan state awal untuk komponen Game di dalam konstruktornya:
class Game extends React.Component {
constructor(props) { super(props); this.state = { history: [{ squares: Array(9).fill(null), }], xIsNext: true, }; }
render() {
return (
<div className="game">
<div className="game-board">
<Board />
</div>
<div className="game-info">
<div>{/* status */}</div>
<ol>{/* TODO */}</ol>
</div>
</div>
);
}
}
Selanjutnya, kita akan membuat komponen Board menerima prop squares
dan onClick
dari komponen Game. Karena sekarang kita sudah memiliki handler untuk klik di dalam Board untuk banyak Square, kita akan perlu memberikan lokasi dari setiap Square ke handler onClick
untuk memberi tahu Square mana yang diklik. Berikut adalah langkah yang diperlukan untuk mengubah komponen Board:
- Menghapus
constructor
di Board. - Mengganti
this.state.squares[i]
denganthis.props.squares[i]
padarenderSquare
di Board. - Mengganti
this.handleClick(i)
denganthis.props.onClick(i)
padarenderSquare
di Board.
Sekarang komponen Board akan terlihat seperti ini:
class Board extends React.Component {
handleClick(i) {
const squares = this.state.squares.slice();
if (calculateWinner(squares) || squares[i]) {
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}
renderSquare(i) {
return (
<Square
value={this.props.squares[i]} onClick={() => this.props.onClick(i)} />
);
}
render() {
const winner = calculateWinner(this.state.squares);
let status;
if (winner) {
status = 'Winner: ' + winner;
} else {
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
}
Kita akan mengubah fungsi render
pada komponen Game agar fungsi tersebut menggunakan entri riwayat terakhir untuk menentukan dan menampilkan status permainan:
render() {
const history = this.state.history; const current = history[history.length - 1]; const winner = calculateWinner(current.squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); }
return (
<div className="game">
<div className="game-board">
<Board squares={current.squares} onClick={(i) => this.handleClick(i)} /> </div>
<div className="game-info">
<div>{status}</div> <ol>{/* TODO */}</ol>
</div>
</div>
);
}
Karena sekarang komponen Game me-render status permainan, kita dapat menghapus kode yang bersangkutan dari method render
Board. Setelah melakukan refactor, fungsi render
Board akan terlihat seperti ini:
render() { return ( <div> <div className="board-row"> {this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
Terakhir, kita perlu memindahkan method handleClick
dari komponen Board ke komponen Game. Kita juga perlu mengubah handleClick
karena state komponen Game memiliki struktur yang berbeda. Di dalam method handleClick
Game, kita menggabungkan (concat) entri riwayat baru ke dalam history
.
handleClick(i) {
const history = this.state.history; const current = history[history.length - 1]; const squares = current.squares.slice(); if (calculateWinner(squares) || squares[i]) {
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
history: history.concat([{ squares: squares, }]), xIsNext: !this.state.xIsNext,
});
}
Catatan
Tidak seperti method
push()
pada senarai, yang mungkin Anda lebih kenal, methodconcat()
tidak melakukan mutate pada senarai sebenarnya, jadi kami lebih memilihconcat()
.
Sampai tahap ini, komponen Board hanya memerlukan method renderSquare
dan render
. State permainan dan method handleClick
seharusnya ada di dalam komponen Game.
Lihat kode lengkap sampai tahap ini
Menampilakan Langkah-Langkah Sebelumnya
Karena kita merekam riwayat permainan tic-tac-toe, sekarang kita dapat menampilkannya ke pemain sebagai daftar langkah sebelumnya.
Kita mengetahui sebelumnya bahwa elemen React adalah object first-class JavaScript; kita dapat mengoperkannya ke manapun pada aplikasi kita. Untuk me-render banyak elemen React, kita dapat menggunakan senarai berisi elemen React.
Di JavaScript, senarai memiliki method map()
yang sering digunakan untuk melakukan pemetaan data ke data lain, contohnya:
const numbers = [1, 2, 3];
const doubled = numbers.map(x => x * 2); // [2, 4, 6]
Dengan menggunakan method map
, kita dapat memetakan riwayat langkah kita ke elemen React yang melambangkan tombol pada layar dan menampilkan daftar tombol untuk “melompat” ke langkah sebelumnya.
Mari menerapkan map
pada history
di method render
Game:
render() {
const history = this.state.history;
const current = history[history.length - 1];
const winner = calculateWinner(current.squares);
const moves = history.map((step, move) => { const desc = move ? 'Go to move #' + move : 'Go to game start'; return ( <li> <button onClick={() => this.jumpTo(move)}>{desc}</button> </li> ); });
let status;
if (winner) {
status = 'Winner: ' + winner;
} else {
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
return (
<div className="game">
<div className="game-board">
<Board
squares={current.squares}
onClick={(i) => this.handleClick(i)}
/>
</div>
<div className="game-info">
<div>{status}</div>
<ol>{moves}</ol> </div>
</div>
);
}
Lihat kode lengkap sampai tahap ini
Untuk setiap langkah pada riwayat permainan tic-tac-toe, kita membuat <li>
yang berisi <button>
. Tombol (<button>
) memiliki handler onClick
yang akan memanggil method bernama this.jumpTo()
. Kita belum mengimplementasikan method jumpTo()
. Untuk sekarang, kita seharusnya sudah melihat daftar langkah yang sudah terjadi dalam permainan dan peringatan pada developer tools console yang bertuliskan:
Warning: Each child in an array or iterator should have a unique “key” prop. Check the render method of “Game”.
Mari membahas makna dari peringatan tersebut.
Memilih Sebuah Key
Ketika kita me-render sebuah list, React menyimpan informasi tentang setiap elemen dalam list yang di-render. Ketika kita memperbarui sebuah list, React perlu menentukan elemen yang sudah berubah. Kita bisa saja menambahkan, menghapus, mengatur ulang, atau memperbarui elemen pada list.
Bayangkan perubahan dari
<li>Alexa: 7 tasks left</li>
<li>Ben: 5 tasks left</li>
ke
<li>Ben: 9 tasks left</li>
<li>Claudia: 8 tasks left</li>
<li>Alexa: 5 tasks left</li>
Selain jumlah yang diperbarui, kemampuan baca manusia mungkin akan mengatakan bahwa kita menukar urutan Ben dan Alexa dan menyisipkan Claudia di antara Alexa dan Ben. Tetapi, React adalah program komputer dan tidak tahu intensi kita. Karena React tidak tahu intensi kita, kita perlu memberikan properti key dari setiap elemen pada list untuk membedakan setiap elemen list dari saudaranya (elemen lain dalam satu hirarki). Salah satu opsi adalah dengan menggunakan string alexa
, ben
, claudia
. Jika kita menampilkan data dari basisdata, ID Alexa, Ben, Claudia pada database dapat digunakan sebagai key.
<li key={user.id}>{user.name}: {user.taskCount} tasks left</li>
** Ketika list di-render ulang, React mengambil seluruh key dari elemen list dan mencari elemen sebelumnya yang memiliki key yang sama. Jika list saat ini memiliki key yang tidak ada sebelumnya, React akan membuat komponen. Jika list saat ini kehilangan sebuah key yang ada pada list sebelumnya, React menghapus (destroy) komponen sebelumnya. Jika ada dua key yang sama, komponen yang bersangkutan dipindahkan. Key memberi tahu React identitas dari tiap komponen, sehingga membuat React dapat mempertahankan state di setiap render ulang. Jika key dari sebuah komponen berubah, komponen akan dihapus dan dibuat ulang dengan state baru.
key
adalah properti khusus dan sudah dipesan di React (bersama dengan ref
, fitur yang lebih lanjut). Ketika sebuah elemen dibuat, React mengekstrak properti key
dan menyimpannya langsung ke elemen yang dikembalikan. Walaupun key
terlihat seperti bagian dari props
, key
tidak dapat diacu menggunakan this.props.key
. React menggunakan key
untuk menentukan komponen yang akan diubah secara otomatis. Sebuah komponen tidak dapat menanyakan key
yang dia miliki.
Kami sangat merekomendasikan Anda untuk memberikan key yang baik ketika membuat list dinamik. Jika Anda tidak memiliki key yang baik, Anda dapat mempertimbangkan restukturisasi data Anda sehingga Anda memiliki key yang baik.
Jika tidak ada key yang diberikan, React akan menampilkan sebuah peringatan dan menggunakan indeks senarai sebagai nilai default. Menggunakan indeks senarai bermasalah ketika kita mencoba untuk mengatur ulang elemen list atau menyisipkan/menghapus elemen list. Memberikan key={i}
secara eksplisit menghilangkan peringatannya, tetapi memiliki masalah yang sama, sehingga tidak direkomendasikan pada banyak kasus.
Key tidak perlu unik secara global. Key hanya perlu unik di antara komponen dan saudaranya.
Mengimplementasikan Penjelajahan Waktu
Di dalam riwayat permainan tic-tac-toe, setiap langkah sebelumnya memiliki ID unik yang bersangkutan dengan langkah tersebut: ID tersebut adalah angka terutut yang melambangkan urutan langkah. Riwayat langkah tidak pernah di atur ulang, dihapus, atau disisipi elemen lain di tengah, jadi pada kasus ini kita dapat menggunakan indeks langkah sebagai key.
Dalam method render
komponen Game, kita dapat menambahkan key sebagai <li key={move}>
dan peringatan React tentang key akan menghilang:
const moves = history.map((step, move) => {
const desc = move ?
'Go to move #' + move :
'Go to game start';
return (
<li key={move}> <button onClick={() => this.jumpTo(move)}>{desc}</button>
</li>
);
});
Lihat kode lengkap sampai tahap ini
Mengklik salah satu tombol pada elemen list akan menghasilkan error karena method jumpTo
tidak didefinisikan (undefined). Sebelum kita mengimplementasikan jumpTo
, kita akan menambahkan stepNumber
di dalam state komponen Game untuk melambangkan langkah yang sedang kita lihat.
Pertama, tambahkan stepNumber: 0
pada state awal di constructor
Game:
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {
history: [{
squares: Array(9).fill(null),
}],
stepNumber: 0, xIsNext: true,
};
}
Kemudian, kita akan mendefinisikan method jumpTo
di dalam Game untuk memperbarui stepNumber
. Kita juga dapat membuat xIsNext
true jika angka yang kita berikan pada stepNumber
adalah genap:
handleClick(i) {
// this method has not changed
}
jumpTo(step) { this.setState({ stepNumber: step, xIsNext: (step % 2) === 0, }); }
render() {
// this method has not changed
}
Sekarang kita akan mengubah beberapa bagian method handleClick
pada Game yang akan dipicu ketika Anda mengklik sebuah persegi.
State stepNumber
yang sudah kita tambahkan menggambarkan langkah yang sedang ditampilkan ke pengguna saat ini. Setelah kita membuat langkah baru, kita perlu memperbarui stepNumber
dengan menambahkan stepNumber: history.length
sebagai bagian dari argumen this.setState
. Hal ini memastikan kita tidak selalu menampilkan langkah yang sama setelah langkah baru berhasil dibuat.
Kita juga akan mengganti this.state.history
dengan this.state.history.slice(0, this.state.stepNumber = 1)
. Hal ini untuk memastikan jika kita “kembali” dan membuat langkah baru dari titik tersebut, kita membuang semua riwayat “masa depan” yang sekarang menjadi tidak benar.
handleClick(i) {
const history = this.state.history.slice(0, this.state.stepNumber + 1); const current = history[history.length - 1];
const squares = current.squares.slice();
if (calculateWinner(squares) || squares[i]) {
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
history: history.concat([{
squares: squares
}]),
stepNumber: history.length, xIsNext: !this.state.xIsNext,
});
}
Terakhir, kita dapat mengubah method render
dari komponen Game dari yang selalu me-render langkah terakhir menjadi me-render langkah yang saat ini dipilih berdasarkan stepNumber
:
render() {
const history = this.state.history;
const current = history[this.state.stepNumber]; const winner = calculateWinner(current.squares);
// sisanya tidak berubah
Jika kita mengklik salah satu langkah pada riwayat permainan, papan tic-tac-toe seharusnya langsung memperbarui dirinya dan menampilkan papan setelah langkah tersebut dijalankan.
Lihat kode penuh sampai saat ini
Ulasan
Selamat! Anda sudah membuat permainan tic-tac-toe yang:
- Memungkinkan Anda bermain tic-tac-toe,
- Memberi tahu pemain yang sudah memenangkan permainan,
- Menyimpan riwayat permainan selama permainan berlangsung,
- Memungkinkan pemain untuk mengulas riwayat permainan dan melihat versi sebelumnya dari papan permainan.
Kerja bagus! Kami berharap sekarang Anda merasa Anda memiliki pemahaman yang baik tentang bagaimana React bekerja.
Lihat hasil akhirnya disini: Hasil Akhir.
Jika Anda memiliki waktu luang atau ingin melatih kemampuan baru React Anda, berikut terdapat beberapa ide untuk perbaikan yang dapat Anda aplikasikan pada permainan tic-tac-toe terurut berdasarkan tingkat kesulitan paling mudah ke yang paling sulit:
- Menampilkan lokasi dari setiap langkah dalam format (kolom, baris) pada daftar riwayat langkah.
- Menebalkan elemen yang sedang dipilih pada daftar langkah.
- Menulis ulang Board sehingga menggunakan dua perulangan untuk membuat persegi, bukan melakukan hardcode.
- Menambahkan toggle yang memungkinkan Anda untuk mengurutkan langkah terutur membesar atau mengecil.
- Ketika salah satu pemain menang, tandai 3 persegi yang membuatnya menang.
- Ketika tidak ada yang menang, tampilan pesan bahwa hasilnya seri.
Melalui tutorial ini, kita menyentuh beberapa konsep React termasuk di dalamnya elemen, komponen, props, dan state. Untuk penjelasan lebih rinci dari setiap topik tersebut, kunjungi dokumentasi. Untuk mempelajari lebih lanjut mengenai cara mendefinisikan komponen, kunjungi Referensi API React.Component
.