Pemisahan kode dengan React.lazy dan Suspense

Anda tidak perlu mengirimkan lebih banyak kode daripada yang diperlukan kepada pengguna, jadi pisahkan paket Anda untuk memastikan hal ini tidak pernah terjadi.

Metode React.lazy memudahkan pemisahan kode aplikasi React di tingkat komponen menggunakan impor dinamis.

import React, { lazy } from 'react';

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

const DetailsComponent = () => (
  <div>
    <AvatarComponent />
  </div>
)

Mengapa ini bermanfaat?

Aplikasi React yang besar biasanya terdiri dari banyak komponen, metode utilitas, dan library pihak ketiga. Jika tidak ada upaya untuk mencoba memuat berbagai bagian aplikasi hanya saat diperlukan, satu bundle JavaScript besar akan dikirimkan kepada pengguna Anda segera setelah mereka memuat halaman pertama. Hal ini dapat memengaruhi performa halaman secara signifikan.

Fungsi React.lazy menyediakan cara bawaan untuk memisahkan komponen dalam aplikasi menjadi beberapa bagian JavaScript yang terpisah dengan sedikit pekerjaan. Anda kemudian dapat menangani status pemuatan saat menggabungkannya dengan komponen Suspense.

Ketegangan

Masalah pengiriman payload JavaScript yang besar kepada pengguna adalah lamanya waktu yang diperlukan halaman untuk selesai dimuat, terutama pada perangkat dan koneksi jaringan yang lebih lemah. Itulah sebabnya pemisahan kode dan pemuatan lambat sangat berguna.

Namun, akan selalu ada sedikit penundaan yang harus dialami pengguna saat komponen pemisahan kode diambil melalui jaringan, jadi penting untuk menampilkan status pemuatan yang berguna. Menggunakan React.lazy dengan komponen Suspense membantu mengatasi masalah ini.

import React, { lazy, Suspense } from 'react';

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

const renderLoader = () => <p>Loading</p>;

const DetailsComponent = () => (
  <Suspense fallback={renderLoader()}>
    <AvatarComponent />
  </Suspense>
)

Suspense menerima komponen fallback yang memungkinkan Anda menampilkan komponen React apa pun sebagai status pemuatan. Contoh berikut menunjukkan cara kerjanya. Avatar hanya dirender saat tombol diklik, yang kemudian membuat permintaan untuk mengambil kode yang diperlukan untuk AvatarComponent yang ditangguhkan. Sementara itu, komponen pemuatan penggantian ditampilkan.

Di sini, kode yang membentuk AvatarComponent berukuran kecil sehingga indikator lingkaran berputar pemuatan hanya ditampilkan dalam waktu singkat. Komponen yang lebih besar dapat memerlukan waktu lebih lama untuk dimuat, terutama pada koneksi jaringan yang lemah.

Untuk lebih menunjukkan cara kerjanya:

  • Untuk melihat pratinjau situs, tekan Lihat Aplikasi. Kemudian, tekan Layar Penuh layar penuh.
  • Tekan `Control+Shift+J` (atau `Command+Option+J` di Mac) untuk membuka DevTools.
  • Klik tab Jaringan.
  • Klik dropdown Pembatasan, yang disetel ke Tidak ada pembatasan secara default. Pilih 3G Cepat.
  • Klik tombol Click Me di aplikasi.

Indikator pemuatan akan ditampilkan lebih lama sekarang. Perhatikan bagaimana semua kode yang membentuk AvatarComponent diambil sebagai potongan terpisah.

Panel jaringan DevTools menampilkan satu file chunk.js yang sedang didownload

Menangguhkan beberapa komponen

Fitur lain dari Suspense adalah memungkinkan Anda menangguhkan pemuatan beberapa komponen, meskipun semuanya dimuat secara lambat.

Contoh:

import React, { lazy, Suspense } from 'react';

const AvatarComponent = lazy(() => import('./AvatarComponent'));
const InfoComponent = lazy(() => import('./InfoComponent'));
const MoreInfoComponent = lazy(() => import('./MoreInfoComponent'));

const renderLoader = () => <p>Loading</p>;

const DetailsComponent = () => (
  <Suspense fallback={renderLoader()}>
    <AvatarComponent />
    <InfoComponent />
    <MoreInfoComponent />
  </Suspense>
)

Cara ini sangat berguna untuk menunda rendering beberapa komponen sekaligus hanya menampilkan satu status pemuatan. Setelah semua komponen selesai mengambil data, pengguna dapat melihat semuanya ditampilkan secara bersamaan.

Anda dapat melihatnya dengan sematan berikut:

Tanpa ini, Anda dapat dengan mudah mengalami masalah pemuatan bertahap, atau berbagai bagian UI dimuat satu demi satu dengan masing-masing memiliki indikator pemuatannya sendiri. Hal ini dapat membuat pengalaman pengguna terasa lebih tidak nyaman.

Menangani kegagalan pemuatan

Suspense memungkinkan Anda menampilkan status pemuatan sementara saat permintaan jaringan dilakukan di balik layar. Namun, bagaimana jika permintaan jaringan tersebut gagal karena alasan tertentu? Anda mungkin sedang offline, atau mungkin aplikasi web Anda sedang mencoba memuat lambat URL berversi yang sudah tidak berlaku, dan tidak lagi tersedia setelah redeployment server.

React memiliki pola standar untuk menangani kegagalan pemuatan jenis ini dengan baik: menggunakan batas error. Seperti yang dijelaskan dalam dokumentasi, komponen React apa pun dapat berfungsi sebagai batas error jika mengimplementasikan salah satu (atau keduanya) metode siklus proses static getDerivedStateFromError() atau componentDidCatch().

Untuk mendeteksi dan menangani kegagalan pemuatan lambat, Anda dapat membungkus komponen Suspense dengan komponen induk yang berfungsi sebagai batas error. Dalam metode render() batas error, Anda dapat merender turunan apa adanya jika tidak ada error, atau merender pesan error kustom jika terjadi masalah:

import React, { lazy, Suspense } from 'react';

const AvatarComponent = lazy(() => import('./AvatarComponent'));
const InfoComponent = lazy(() => import('./InfoComponent'));
const MoreInfoComponent = lazy(() => import('./MoreInfoComponent'));

const renderLoader = () => <p>Loading</p>;

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = {hasError: false};
  }

  static getDerivedStateFromError(error) {
    return {hasError: true};
  }

  render() {
    if (this.state.hasError) {
      return <p>Loading failed! Please reload.</p>;
    }

    return this.props.children;
  }
}

const DetailsComponent = () => (
  <ErrorBoundary>
    <Suspense fallback={renderLoader()}>
      <AvatarComponent />
      <InfoComponent />
      <MoreInfoComponent />
    </Suspense>
  </ErrorBoundary>
)

Kesimpulan

Jika Anda tidak yakin harus mulai dari mana untuk menerapkan pemisahan kode ke aplikasi React, ikuti langkah-langkah berikut:

  1. Mulai di tingkat rute. Rute adalah cara paling sederhana untuk mengidentifikasi titik-titik aplikasi Anda yang dapat dibagi. Dokumen React menunjukkan cara penggunaan Suspense bersama dengan react-router.
  2. Identifikasi komponen besar di halaman situs Anda yang hanya dirender pada interaksi pengguna tertentu (seperti mengklik tombol). Memisahkan komponen ini akan meminimalkan payload JavaScript Anda.
  3. Pertimbangkan untuk memisahkan hal lain yang berada di luar layar dan tidak penting bagi pengguna.