ReactJS

Belum masuk. Progresmu tidak tersimpan.

Masuk
  • Bab 10 dari 10
  • 35 menit
  • 1 latihan kode
  • 4 soal kuis

Performa, Testing, dan Publikasi

Di bab ini (10 bagian)
  1. Tujuan
  2. Optimasi: ukur dulu, baru perbaiki
  3. Testing dengan Vitest dan React Testing Library
  4. Build dan deploy
  5. Melangkah ke Next.js
  6. Studi kasus: aplikasi daftar tugas
  7. Praktik terbaik
  8. Kesalahan umum
  9. Roadmap belajar
  10. Rangkuman

Tujuan bab ini

  • Mengukur dan memperbaiki performa dengan React DevTools Profiler, memo, lazy + Suspense, dan virtualisasi list.
  • Menulis tes komponen dengan Vitest dan React Testing Library.
  • Mem-build dan mempublikasikan aplikasi Vite ke Vercel, Netlify, atau GitHub Pages, lalu tahu kapan melangkah ke Next.js.
  • Merangkum praktik terbaik, kesalahan umum, dan roadmap belajar lewat studi kasus aplikasi daftar tugas.

Optimasi: ukur dulu, baru perbaiki

Kebanyakan aplikasi React sudah cukup cepat tanpa trik apa pun. Optimasi yang ditebak-tebak sering cuma menambah kode rumit. Jadi langkah pertama selalu mengukur.

Pasang ekstensi React DevTools di browser, buka tab Profiler, tekan rekam, lakukan aksi yang terasa lambat, lalu berhenti. Kamu akan melihat komponen mana yang render, berapa kali, dan berapa milidetik. Baru setelah tahu biang keroknya, pilih alat yang tepat.

Optimasi performa aplikasi

memo

Saat induk render ulang, semua anaknya ikut render, walaupun props mereka tidak berubah. memo membungkus komponen supaya React melewati render bila props-nya sama (dibandingkan dengan Object.is).

import { memo } from 'react';

const KartuProduk = memo(function KartuProduk({ nama, harga }) {
  return <div>{nama}: Rp{harga}</div>;
});

memo tidak membuat komponen "tidak pernah render ulang". Ia tetap render bila props berubah, atau bila state dan context miliknya berubah. Hati-hati juga: objek dan fungsi baru yang dibuat setiap render (onPilih={() => ...}) selalu dianggap props baru. Di situ useCallback dan useMemo membantu. Kabar baiknya, React Compiler (rilis stabil 1.0 pada 2025) bisa menambahkan memoization ini otomatis saat build.

lazy dan Suspense

Secara bawaan, Vite menggabungkan semua halaman jadi satu bundel. Halaman berat seperti dasbor admin bisa dipisah dan baru diunduh saat dibuka:

import { lazy, Suspense } from 'react';

const Dasbor = lazy(() => import('./Dasbor'));

function App() {
  return (
    <Suspense fallback={<p>Memuat halaman...</p>}>
      <Dasbor />
    </Suspense>
  );
}

Selama file Dasbor diunduh, Suspense menampilkan fallback. Komponen yang di-lazy harus di-export default.

Virtualisasi list

Merender 10.000 baris berarti 10.000 elemen DOM, padahal layar hanya memuat sekitar 20. Virtualisasi hanya merender baris yang terlihat dan menukar isinya saat kamu scroll. Pakai pustaka seperti TanStack Virtual atau react-window saat daftar sudah ribuan baris. Untuk puluhan item, tidak perlu.

Testing dengan Vitest dan React Testing Library

Tes menjaga fitur tetap jalan saat kamu merombak kode. Untuk proyek Vite, pasangan paling umum adalah Vitest (menjalankan tes, API-nya mirip Jest) dan React Testing Library (merender komponen dan berinteraksi seperti pengguna).

npm install -D vitest jsdom @testing-library/react @testing-library/user-event @testing-library/jest-dom

Di vite.config.js tambahkan test: { environment: 'jsdom' } agar ada document palsu. Lalu tulis tes:

// Penghitung.test.jsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom/vitest';
import { test, expect } from 'vitest';
import Penghitung from './Penghitung';

test('angka bertambah saat tombol diklik', async () => {
  const user = userEvent.setup();
  render(<Penghitung />);

  await user.click(screen.getByRole('button', { name: 'Tambah' }));

  expect(screen.getByText('Jumlah klik: 1')).toBeInTheDocument();
});

Jalankan dengan npx vitest. Tiga pemain utamanya: render memasang komponen, screen mencari elemen, userEvent meniru klik dan ketikan sungguhan (termasuk fokus dan urutan event). Prinsipnya: uji yang dilihat pengguna. Cari elemen lewat peran dan teks (getByRole, getByText), bukan nama class CSS. Logika murni seperti reducer dan fungsi validasi lebih gampang lagi: cukup panggil fungsinya dan cek hasilnya.

Build dan deploy

Saat development, Vite menyajikan file satu per satu agar cepat diubah. Untuk produksi, jalankan:

npm run build     # hasil di folder dist/
npm run preview   # coba hasil build di http://localhost:4173

Folder dist berisi index.html dan file JS/CSS yang sudah di-minify dengan nama ber-hash (index-B7x2k.js) agar cache browser selalu benar. Isinya file statis, jadi bisa diunggah ke hosting mana pun. Variabel lingkungan untuk browser wajib diawali VITE_ dan dibaca dengan import.meta.env.VITE_API_URL. Ingat, semua yang ada di bundel bisa dilihat orang, jadi jangan simpan kunci rahasia di sana.

PlatformCaraCatatan
VercelHubungkan repo GitHub, preset Vite terdeteksi otomatisSetiap push ke main langsung ter-deploy
NetlifyHubungkan repo, build npm run build, folder distUntuk React Router tambahkan public/_redirects berisi /* /index.html 200
GitHub PagesUnggah dist lewat GitHub ActionsSet base: '/nama-repo/' di vite.config.js

Kalau memakai React Router, server harus mengembalikan index.html untuk semua alamat, agar membuka /produk/7 langsung tidak berakhir 404.

Melangkah ke Next.js

React + Vite merender di browser (CSR): pengguna mengunduh JavaScript dulu, baru halaman muncul. Untuk blog, toko online, atau halaman yang butuh SEO, Next.js menyiapkan HTML di server (SSR) atau saat build (SSG). Ia juga punya routing berbasis folder (app/produk/[id]/page.jsx jadi /produk/:id), Server Components, serta optimasi gambar dan font. Semua yang kamu pelajari (komponen, props, state, hooks) tetap berlaku karena Next.js dibangun di atas React. Mulai dengan npx create-next-app@latest.

Studi kasus: aplikasi daftar tugas

Aplikasi daftar tugas merangkum hampir semua konsep kelas ini: useState, controlled input, map + key, update immutable, dan event handler.

function AplikasiTugas() {
  const [tugas, setTugas] = useState([]);
  const [teks, setTeks] = useState('');

  function tambah(e) {
    e.preventDefault();
    if (!teks.trim()) return;
    setTugas([...tugas, { id: crypto.randomUUID(), judul: teks.trim(), selesai: false }]);
    setTeks('');
  }
  const toggle = (id) => setTugas(tugas.map((t) => (t.id === id ? { ...t, selesai: !t.selesai } : t)));
  const hapus = (id) => setTugas(tugas.filter((t) => t.id !== id));
  const sisa = tugas.filter((t) => !t.selesai).length; // dihitung, bukan state

  return (
    <>
      <form onSubmit={tambah}>
        <input value={teks} onChange={(e) => setTeks(e.target.value)} />
        <button>Tambah</button>
      </form>
      <ul>
        {tugas.map((t) => (
          <li key={t.id}>
            <input type="checkbox" checked={t.selesai} onChange={() => toggle(t.id)} />
            {t.judul} <button onClick={() => hapus(t.id)}>Hapus</button>
          </li>
        ))}
      </ul>
      <p>{sisa} tugas tersisa</p>
    </>
  );
}

Coba kembangkan: filter Semua/Aktif/Selesai, simpan ke localStorage, atau ubah jadi useReducer. Latihan di bab ini melatih logika itu sebagai fungsi murni.

Praktik terbaik

  • Komponen kecil dengan satu tanggung jawab; pindahkan logika berulang ke custom hook.
  • Nama jelas: DaftarProduk, handleSubmit, isLoading.
  • Struktur folder konsisten sejak awal, misalnya components/, pages/, hooks/.
  • Aktifkan ESLint (termasuk aturan react-hooks) dan Prettier, lalu pertimbangkan TypeScript.

Kesalahan umum

  • Mengubah state langsung. tugas.push(x) tidak memicu render; buat array baru.
  • Indeks sebagai key. Tampilan kacau saat list diurutkan atau item dihapus; pakai ID.
  • Lupa array dependensi useEffect. Efek jalan tiap render dan bisa berputar tanpa akhir.
  • Menyimpan nilai turunan di state. sisa cukup dihitung dari tugas.
  • Prop drilling berlapis-lapis. Pakai Context bila sudah terasa berat.
  • onClick={hapus()}. Fungsi langsung jalan saat render; tulis onClick={() => hapus(id)}.
  • Optimasi tanpa mengukur. Buka Profiler dulu sebelum menaburkan memo.

Roadmap belajar

  1. Fondasi (1-2 minggu): HTML, CSS, JavaScript modern, map/filter/reduce, destructuring, spread.
  2. Dasar React (2-3 minggu): JSX, komponen, props, useState, event, list, render bersyarat.
  3. Menengah (3-4 minggu): useEffect dan API, React Router, form, Context, custom hook.
  4. Lanjutan (berkelanjutan): TypeScript, testing, Next.js, performa, CI/CD.

Belajar paling efektif lewat proyek: kalkulator, daftar tugas, katalog film dari API publik, lalu aplikasi dengan login. Rujukan utama: react.dev, reactrouter.com, vite.dev, dan testing-library.com.

Rangkuman

  • Ukur dengan React DevTools Profiler sebelum optimasi; pakai memo, lazy + Suspense, dan virtualisasi hanya bila terbukti perlu.
  • Vitest + React Testing Library menguji komponen dari sudut pandang pengguna lewat render, screen, dan userEvent.
  • npm run build menghasilkan folder dist berisi file statis yang bisa di-deploy ke Vercel, Netlify, atau GitHub Pages.
  • Next.js menambahkan SSR, SSG, dan routing berbasis folder di atas React.
  • Studi kasus daftar tugas merangkum state, controlled input, list dengan key, dan update immutable.

Selesaikan bab ini

  1. 1. Baca materi
  2. 2. Latihan kode (1)
  3. 3. Kuis (4 soal)

Latihan kode: Logika aplikasi daftar tugas

Pisahkan logika studi kasus daftar tugas menjadi fungsi murni. Di komponen, misalnya setTugas(tambahTugas(tugas, teks, crypto.randomUUID())), setTugas(toggleTugas(tugas, id)), lalu saringTugas(tugas, filter).map(...) untuk dirender dan hitungSisa(tugas) untuk teks "n tugas tersisa". Setiap tugas berbentuk { id, judul, selesai }. Jangan ubah array atau objek lama.

  • tambahTugas(daftar, judul, id): bila judul.trim() kosong, kembalikan daftar yang sama. Bila tidak, kembalikan array baru dengan tugas { id, judul: judul.trim(), selesai: false } di akhir.
  • toggleTugas(daftar, id): balik nilai selesai tugas dengan id itu.
  • hapusTugas(daftar, id): buang tugas dengan id itu.
  • saringTugas(daftar, filter): 'aktif' hanya yang belum selesai, 'selesai' hanya yang selesai, selain itu semua.
  • hitungSisa(daftar): jumlah tugas yang belum selesai.

Cek pemahaman

  1. 1Apa teks yang tampil saat elemen di baris terakhir dirender?

    function Sisa({ tugas }) {
      const sisa = tugas.filter((t) => !t.selesai).length;
      return <p>{sisa > 0 ? `Sisa ${sisa} tugas` : 'Semua beres!'}</p>;
    }
    
    <Sisa tugas={[
      { id: 1, selesai: true },
      { id: 2, selesai: false },
      { id: 3, selesai: false },
    ]} />
  2. 2Pada proyek Vite, npm run build menyimpan hasil build produksi di folder...

  3. 3Komponen yang dibungkus memo tidak akan pernah render ulang sama sekali.

  4. 4Di React Testing Library, cara mencari tombol "Tambah" yang paling disarankan adalah...