Event secara bahasa artinya kejadian. Pada Javascript: Event adalah kejadian yang terjadi pada element di halaman web. Kejadian yang dimaksud di sini seperti aktivitas yang dikerjakan pada halaman web. Misalnya seperti:

Jadi perlu adanya sebuah mekanisme untuk menangkap event tersebut, dan biasa disebut dengan Event Handler. Dalam javascript terdapat beberapa event handle diantaranya

React memungkinkan Anda menambahkan event handler ke dalam file JSX. Event handler adalah fungsi-fungsi yang akan dipicu sebagai respons terhadap interaksi seperti mengeklik, mengarahkan kursor, memfokuskan pada input formulir, dan sebagainya.

React/Nextjs memiliki event handler untuk merespon event yang dilakukan oleh pengguna di sebuah halaman website. Untuk menambahkan event handler, pertama-tama kita akan mendefinisikan sebuah fungsi dan kemudianmengopernya sebagai prop ke tag JSX yang sesuai.

Pada pertemuan ini, kita buat repository baru dengan nama 04-event-dan-state

Langkah 1

Kita mencoba membuat tombol sederhana yang belum bisa melakukan apa-apa alias belum kita buat event handler untuk tombol tersebut. Sebagai contoh, berikut adalah sebuah tombol yang belum melakukan apa pun. Kita buat folder/file baru di src/component/button.tsx

Selanjutnya pada file src/app/page.tsx kita ubah menjadi seperti berikut

Kemudian kita jalankan perintah "npm run dev" dan kita buka alamat localhost:3000 pada browser. Maka akan tampil hasil seperti berikut

Langkah 2

Kita bisa menambahkan event pada tombol tersebut. Seperti contoh kita buat ketika tombol di klik, akan memunculkan notif/alert. Kita dapat membuat pesan ketika pengguna mengeklik dengan mengikuti tiga langkah berikut:

  1. Deklarasikan sebuah fungsi bernama handleClick di dalam komponen Button kita.
  2. Implementasikan logika di dalam fungsi tersebut (gunakan alert untuk menampilkan pesan).
  3. Tambahkan handler onClick={handleClick} ke tag JSX < button >

Perhatikan kode button.tsx berikut

Jika terjadi error seperti gambar berikut

Maka kita butuh mengatur agar komponen yang kita gunakan menjadi komponen client. Untuk menjadikan komponen client, kita cukup memberikan perintah ini "use client"; pada baris pertama file page.tsx

Kita mendefinisikan fungsi handleClick dan kemudian mengopernya sebagai prop ke < button >. Method handleClick adalah sebuah event handler pada tombol tersebut.

Nama Method event handler sebaiknya memiliki format tertentu, seperti contoh memiliki nama yang diawali dengan kata handle, diikuti oleh nama event yang akan dilakukan. Contoh

Selain itu, sebagai alternatif, Kita juga dapat mendefinisikan event handler secara inline dalam JSX secara langsung seperti berikut

Fungsi di oper (benar)

Fungsi dipanggil/call (salah)

< button onClick={handleClick} >

< button onClick={handleClick()} >

Perbedaannya tipis. Pada contoh pertama, fungsi handleClick dioper sebagai event handler onClick. Ini memberitahu React untuk mengingatnya dan hanya memanggil fungsi tersebut ketika pengguna mengeklik tombolnya.

Pada contoh kedua, tanda () di akhir handleClick() akan menjalankan fungsi tersebut langsung saat proses render, tanpa adanya klik. Ini karena JavaScript di dalam tag JSX { dan } dieksekusi secara langsung.

Karena event handler dideklarasikan di dalam komponen, event handler memiliki akses ke props komponen tersebut. Jadi isi dari event handler bisa di definisikan di props. Hal ini mempermudah kita dalam membuat komponen yang isi/kontennya dinamis, menyesuaikan pada layout.

Kita buat fungsi baru pada component button.tsx

Parameter isiPesan dan namaTombol bisa diisi oleh layout yang ada di page.tsx nanti, sehingga komponen Tombol_2 bernilai dinamis.

Sekarang kita modifikasi file page.tsx seperti berikut

Coba cek di browser dan amati apa yang terjadi?

Jelaskan mengapa bisa seperti itu?

Event handler akan menangkap event dari child mana pun yang mungkin dimiliki oleh komponen parent. Kita sebut bahwa sebuah event bisa "menggelembung" (bubbles) atau "berpropagasi" ke ata/parent: mulai dari elemen tempat event terjadi, dan bergerak ke atas pada parent element.

Langkah 1 - Propagation

Sebagai contoh coba kita modifikasi file button.tsx seperti berikut

Kemudian kita modifikasi fiile page.tsx

Kemudian kita jalankan di browser, coba klik Tombol-1, dan amati apa yang terjadi?

Kita akan disuguhkan dengan pesan/alert sebanyak 2 kali, yaitu Pesan "Child Element : Tombol-1" dan pesan "Parent Element : Div".

Hal ini terjadi karena baik untuk element div maupun button memiliki event yang sama yaitu onClick, sehingga ketika button diklik maka event handler untuk onClick pada button akan dijalankan. Kemudian baru event handler dari parent (element div) akan dijalankan.

Hal ini disebut dengan propagation, dan biasa terjadi pada elemen child dan parent yang memiliki event yang sama.

Menghentikan Propagation

Event handler menerima sebuah objek event sebagai satu-satunya argumen/parameter. Berdasarkan konvensi, objek tersebut biasanya ditulis e yang merupakan kepanjangan dari "event". Anda dapat menggunakan objek ini untuk membaca informasi tentang event tersebut.

Objek event tersebut juga dapat memungkinkan untuk menghentikan propagasi. Jika kita ingin mencegah sebuah event untuk mencapai komponen induknya (propagation), Kita harus memanggil e.stopPropagation() untuk mencegah propagasi.

Langkah 2 - Stop Propagation

Seringkali komponen perlu mengubah tampilan di layar sebagai respons akan terjadinya interaksi dari pengguna. Seperti contoh

Komponen perlu "mengingat" informasi-informasi yang telah dilakukan pengguna seperti nilai kolom input, gambar yang dipilih, dan isi keranjang belanja.

Dalam React, ingatan (memory) yang dimiliki komponen disebut state.

Langkah 1

Kita buat file data dummy untuk mencoba state pada src/data/article.tsx yang berisi seperti berikut

export const sculptureList = [{
    name: 'Homenaje a la Neurocirugía',
    artist: 'Marta Colvin Andrade',
    description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.',
    url: 'https://i.imgur.com/Mx7dA2Y.jpg',
    alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'  
  }, {
    name: 'Floralis Genérica',
    artist: 'Eduardo Catalano',
    description: 'This enormous (75 ft. or 23m) silver flower is located in Buenos Aires. It is designed to move, closing its petals in the evening or when strong winds blow and opening them in the morning.',
    url: 'https://i.imgur.com/ZF6s192m.jpg',
    alt: 'A gigantic metallic flower sculpture with reflective mirror-like petals and strong stamens.'
  }, {
    name: 'Eternal Presence',
    artist: 'John Woodrow Wilson',
    description: 'Wilson was known for his preoccupation with equality, social justice, as well as the essential and spiritual qualities of humankind. This massive (7ft. or 2,13m) bronze represents what he described as "a symbolic Black presence infused with a sense of universal humanity."',
    url: 'https://i.imgur.com/aTtVpES.jpg',
    alt: 'The sculpture depicting a human head seems ever-present and solemn. It radiates calm and serenity.'
  }, {
    name: 'Moai',
    artist: 'Unknown Artist',
    description: 'Located on the Easter Island, there are 1,000 moai, or extant monumental statues, created by the early Rapa Nui people, which some believe represented deified ancestors.',
    url: 'https://i.imgur.com/RCwLEoQm.jpg',
    alt: 'Three monumental stone busts with the heads that are disproportionately large with somber faces.'
  }, {
    name: 'Blue Nana',
    artist: 'Niki de Saint Phalle',
    description: 'The Nanas are triumphant creatures, symbols of femininity and maternity. Initially, Saint Phalle used fabric and found objects for the Nanas, and later on introduced polyester to achieve a more vibrant effect.',
    url: 'https://i.imgur.com/Sd1AgUOm.jpg',
    alt: 'A large mosaic sculpture of a whimsical dancing female figure in a colorful costume emanating joy.'
  }];

Kemudian kita coba buat komponen baru di src/component/gallery.tsx

Kita panggil komponen tersebut pada page.tsx

Sekarang coba di browser dan klik tombol "Artikel Selanjutnya" dan perhatikan apa yang terjadi?

Ya, tidak terjadi apa-apa 😀

Event handler handleClick memperbarui nilai variabel index. Namun dua hal mencegah pembaruan tersebut ditampilkan ke pengguna:

  1. Variabel lokal tidak dipertahankan antar-render. Saat React me-render komponen ini untuk kedua kalinya, react membuat ulang dari awal, sehingga index tetap bernilai 0 dan react tidak memperhatikan adanya perubahan ke variabel index tersebut.
  2. Perubahan terhadap variabel lokal tidak memicu render. React tidak menyadari kalau dia perlu melakukan render ulang dengan data yang baru.

Untuk memperbarui komponen dengan data baru, dua hal perlu terjadi:

  1. Mempertahankan data antar-render.
  2. Memicu React untuk merender ulang komponennya dengan data baru.

Dua hal tersebut bisa dicapai dengan HookuseState:

  1. Sebuah variabel state untuk mempertahankan data antar-render.
  2. Sebuah fungsi state setter untuk memperbarui variabel dan memicu React untuk merender ulang komponen.

Langkah 2: Menambahkan variabel state

Untuk menambahkan variabel state, import useState dari React di paling atas file src/components/gallery.tsx

import { useState } from 'react';

Lalu, ubah baris berikut:

let index = 0;

Menjadi

const [index, setIndex] = useState(0);

index merupakan variabel state dan setIndex adalah fungsi setter.

Ubah fungsi dalam handleClick menjadi seperti ini

function handleClick() {
    setIndex(index + 1);  // counter index + 1, utk melihat data selanjutnya
}

Maka kode pada gallery.tsx seperti berikut

Jalankan pada browser dan amati apa yang terjadi?

Seiring berkembangnya aplikasi kita, penting untuk memperhatikan bagaimana state diatur dan memperhatikan bagaimana data mengalir diantara komponen-komponen yang ada. State yang redundan atau duplikat adalah sumber dari bug di kemudian hari. Dalam bab ini, Kita akan belajar bagaimana menata state dengan baik, bagaimana menjaga logika pembaruan state agar mudah dikelola, dan bagaimana dapat berbagi state dengan komponen yang lain.

Dalam React, kita tidak perlu mengubah kode secara langsung untuk mengubah user interface (UI). Misalnya, tombol submit tidak akan muncul/dinonaktifkan sebelum pengguna menginputkan form secara lengkap.

Berikut contoh form yang dibangun menggunakan React. Perhatikan bagaimana ia menggunakan variabel state status untuk menentukan apakah tombol kirim diaktifkan atau dinonaktifkan, dan apakah pesan sukses ditampilkan sebagai gantinya.

Langkah 1

Kita buat komponen baru src/components/form.tsx

Kemudian kita tambahkan kode pada file page.tsx

Jalankan pada browser, amati dan laporkan apa yang terjadi?

Mengatur struktur state dengan baik dapat membuat perbedaan antara komponen yang mudah dimodifikasi dan di-debug, dan komponen yang selalu menjadi sumber error. Perlu dicatat bahwa state

tidak boleh mengandung informasi yang tidak perlu atau duplikat. Karena jika ada state yang tidak perlu, mudah untuk lupa memperbarui state tersebut, yang akhirnya memperkenalkan masalah baru!

Misalnya, formulir ini memiliki variabel state fullName yang redundan:

Langkah 2

Kita tambahkan kode berikut pada src/component/form.tsx

Kemudian tambahkan ke page.tsx

Jalankan pada browser dan amati...!!!

Kita tahu bahwa state fullName hanya merupakan gabungan string dari state firstName dan lastName. Hal ini membuat state redundan, dan bisa membuat kesalahan/bug pada aplikasi react/nextjs. Untuk itu, state fullName bisa dihapus dan digantikan variable biasa.

Coba perhatikan dan implementasikan kode berikut pada src/component/form.tsx

Jalankan pada browser dan amati apa yang terjadi?

Terkadang, kita ingin state dari dua komponen yang berbeda selalu berubah bersama. Untuk melakukannya, hapus state dari keduanya, pindahkan state tersebut ke bagian induk (parent) yang paling berdekatan, dan kemudian teruskan ke kedua komponen melalui props. Hal ini dikenal sebagai "lifting state up", dan ini adalah salah satu hal lumrah saat menulis kode React.

Pada contoh ini, dalam satu waktu hanya akan ada satu panel yang aktif. Untuk mencapainya, daripada menyimpan state aktif di setiap panel secara individu, komponen induk menyimpan state dan menentukan props untuk anak-anaknya.

Langkah 1

Kita buat file komponen pada src/components/accordion.tsx

Lalu kita tambahkan component Accordion ke file page.tsx

Amati dan laporkan apa yang terjadi?

Saat kita me-render ulang sebuah komponen, React perlu memutuskan bagian pohon mana yang dipertahankan (dan diperbarui), serta bagian mana yang harus dibuang atau direset seperti awal/semula. Pada kebanyakan kasus, perilaku otomatis React ini sudah cukup baik. Secara default, React akan mempertahankan bagian-bagian pohon yang "cocok" dengan struktur pohon yang sebelumnya telah di-render.

Namun, ada kalanya hal ini bukan yang kita harapkan. Seperti contoh aplikasi pada chat berikut, dimana ketika kita mengetik pesan ke si-A dan kemudian berpindah chat ke si-B, dan ternyata pesan yang ditulis tidak sesuai. Hal ini bisa membuat pengguna secara tidak sengaja mengirim pesan ke orang yang salah.

Langkah 2

Kita buat file di src/components/chat.tsx

React memungkinkan Anda untuk mengesampingkan perilaku default, dan memaksa sebuah komponen untuk mengatur ulang statusnya (state) dengan memberikan key yang berbeda, seperti < Chat key={email} / >. Hal ini memberitahu React bahwa jika penerima berbeda, itu harus dianggap sebagai komponen Chat yang berbeda yang perlu dibuat kembali dari awal dengan data (dan UI seperti input) yang baru. Sekarang, beralih antara penerima mengatur ulang input - meskipun Anda me-render komponen yang sama.

Perhatikan fungsi Messenger, dan ubah baris kode ini

<Chat contact={to} />

Menjadi

<Chat key={to.email} contact={to} />

Coba jalankan kembali pada browser, amati dan laporkan perbedaannya.