00:00:00(musik ceria) - Oke, halo semuanya.
00:00:06Nama saya Aurora.
00:00:07Saya seorang pengembang web dari Norwegia.
00:00:09Saya bekerja sebagai konsultan di Crane Consulting dan saya juga aktif membangun dengan Next.js app router dalam proyek konsultasi saya saat ini.
00:00:16Hari ini,
00:00:17saya akan mengajarkan pola-pola terkait komposisi,
00:00:19caching,
00:00:20dan arsitektur di Next.js modern yang akan membantu Anda memastikan skalabilitas dan performa.
00:00:24Izinkan saya menyegarkan kembali konsep paling fundamental untuk presentasi ini,
00:00:28yaitu rendering statis dan dinamis.
00:00:30Kita menemui keduanya di Next.js app router.
00:00:33Rendering statis memungkinkan kita membangun situs web yang lebih cepat karena konten yang sudah dirender sebelumnya dapat di-cache dan didistribusikan secara global,
00:00:40memastikan pengguna dapat mengaksesnya lebih cepat.
00:00:42Contohnya, situs web Next.js Conf.
00:00:46Rendering statis mengurangi beban server karena konten tidak perlu dibuat untuk setiap permintaan pengguna.
00:00:51Konten yang sudah dirender sebelumnya juga lebih mudah diindeks oleh perayap mesin pencari karena konten sudah tersedia saat halaman dimuat.
00:00:58Rendering dinamis,
00:00:59di sisi lain,
00:01:00memungkinkan aplikasi kita menampilkan data real-time atau yang sering diperbarui.
00:01:05Ini juga memungkinkan kita menyajikan konten yang dipersonalisasi,
00:01:08seperti dasbor dan profil pengguna.
00:01:09Contohnya, dasbor Vercel.
00:01:12Dengan rendering dinamis,
00:01:13kita bisa mengakses informasi yang hanya bisa diketahui pada saat permintaan.
00:01:16Dalam kasus ini,
00:01:17pengguna mana yang mengakses dasbor mereka,
00:01:19yaitu saya.
00:01:20Ada API tertentu yang dapat menyebabkan halaman dirender secara dinamis.
00:01:25Penggunaan prop `params` dan `searchParams` yang diteruskan ke halaman atau hook yang setara akan menyebabkan rendering dinamis.
00:01:32Namun,
00:01:32dengan `params`,
00:01:33kita dapat menentukan serangkaian halaman yang sudah dirender sebelumnya menggunakan `static params` generik,
00:01:37dan kita juga dapat melakukan cache halaman saat dibuat oleh pengguna.
00:01:40Selain itu,
00:01:41membaca cookie dan header permintaan yang masuk akan membuat halaman memilih rendering dinamis.
00:01:46Namun,
00:01:47tidak seperti `params`,
00:01:48mencoba melakukan cache atau pra-render apa pun menggunakan header atau cookie akan menimbulkan kesalahan saat build karena informasi tersebut tidak dapat diketahui sebelumnya.
00:01:56Terakhir,
00:01:56menggunakan `fetch` dengan konfigurasi cache data `no-store` juga akan memaksa rendering dinamis.
00:02:00Jadi ini adalah beberapa,
00:02:02ada beberapa API lagi yang dapat menyebabkan rendering dinamis,
00:02:04tetapi ini adalah yang paling sering kita temui.
00:02:06Pada versi Next sebelumnya,
00:02:08sebuah halaman akan dirender baik sebagai statis penuh atau dinamis penuh.
00:02:13Satu API dinamis di sebuah halaman akan membuat seluruh halaman memilih rendering dinamis.
00:02:17Contohnya,
00:02:18melakukan pemeriksaan otentikasi sederhana untuk nilai cookie.
00:02:20Dengan memanfaatkan komponen server React dengan `Suspense`,
00:02:23kita dapat mengalirkan konten dinamis seperti spanduk selamat datang yang dipersonalisasi atau rekomendasi saat siap,
00:02:29dan hanya menyediakan fallback dengan `Suspense` sambil menampilkan konten statis seperti buletin.
00:02:34Namun,
00:02:34setelah kita menambahkan beberapa komponen asinkron pada halaman dinamis seperti produk unggulan,
00:02:39komponen tersebut juga akan berjalan pada waktu permintaan meskipun tidak bergantung pada API dinamis.
00:02:45Jadi,
00:02:45untuk menghindari pemblokiran pemuatan halaman awal,
00:02:48kita akan menangguhkan dan mengalirkan komponen-komponen tersebut juga,
00:02:51melakukan pekerjaan ekstra,
00:02:52membuat kerangka,
00:02:53dan mengkhawatirkan hal-hal seperti pergeseran tata letak.
00:02:56Namun,
00:02:56halaman seringkali merupakan campuran konten statis dan dinamis.
00:03:01Contohnya,
00:03:01aplikasi e-commerce yang bergantung pada informasi pengguna tetapi masih berisi sebagian besar data statis.
00:03:07Dipaksa memilih di antara keduanya,
00:03:09antara statis atau dinamis,
00:03:11menyebabkan banyak pemrosesan berlebihan di server pada konten yang tidak pernah atau sangat jarang berubah dan tidak optimal untuk performa.
00:03:19Jadi untuk mengatasi masalah ini,
00:03:21pada Next.js Conf tahun lalu,
00:03:23direktif `use cache` diumumkan.
00:03:26Dan tahun ini,
00:03:27seperti yang kita lihat di keynote,
00:03:29itu tersedia di Next.js 16.
00:03:30Jadi dengan `use cache`,
00:03:32halaman tidak lagi dipaksa menjadi rendering statis atau dinamis.
00:03:36Keduanya bisa.
00:03:37Dan Next.js tidak perlu lagi menebak jenis halaman berdasarkan apakah halaman tersebut mengakses hal-hal seperti `params`.
00:03:43Semuanya dinamis secara default dan `use cache` memungkinkan kita secara eksplisit memilih untuk melakukan caching.
00:03:47`Use cache` memungkinkan caching yang dapat disusun.
00:03:51Kita bisa menandai halaman,
00:03:53komponen React,
00:03:53atau fungsi sebagai dapat di-cache.
00:03:55Di sini,
00:03:56kita sebenarnya bisa melakukan cache komponen produk unggulan karena tidak memerlukan permintaan dan pemrosesan serta tidak menggunakan API dinamis.
00:04:03Dan segmen cache ini dapat dirender sebelumnya dan disertakan sebagai bagian dari shell statis dengan pra-rendering parsial,
00:04:10artinya produk unggulan sekarang tersedia saat halaman dimuat dan tidak perlu di-stream.
00:04:14Jadi sekarang setelah kita memiliki pengetahuan latar belakang yang penting ini,
00:04:18mari kita lakukan demo.
00:04:19Peningkatan pada basis kode dengan masalah umum yang sering ditemui di aplikasi Next.js.
00:04:24Ini termasuk `prop drilling` yang dalam,
00:04:25membuatnya sulit untuk memelihara dan memfaktorkan ulang fitur,
00:04:28JavaScript sisi klien yang berlebihan dan komponen besar dengan banyak tanggung jawab,
00:04:31serta kurangnya rendering statis,
00:04:33yang menyebabkan biaya server tambahan dan performa yang menurun.
00:04:36Baiklah, mari kita mulai.
00:04:37Dan beri saya waktu sebentar di sini.
00:04:50Oke, bagus.
00:04:54Jadi ini adalah aplikasi yang sangat sederhana.
00:04:56Ini terinspirasi dari platform e-commerce.
00:04:59Dan izinkan saya melakukan demo awal di sini.
00:05:01Jadi saya bisa memuat halaman ini.
00:05:03Saya punya beberapa konten seperti produk unggulan ini.
00:05:06Saya punya kategori unggulan, data produk yang berbeda.
00:05:09Ada juga halaman Jelajahi Semua di sini tempat saya bisa melihat semua produk di platform dan berpindah halaman di antaranya.
00:05:20Lalu kita punya halaman Tentang di sini, yang hanya statis.
00:05:24Saya juga bisa masuk sebagai pengguna.
00:05:27Dan itu akan membuat saya masuk ke akun pengguna saya.
00:05:30Dan juga mendapatkan konten yang dipersonalisasi di dasbor saya di sini.
00:05:33Seperti misalnya,
00:05:34produk yang direkomendasikan atau diskon yang dipersonalisasi ini.
00:05:38Jadi perhatikan di sini, ada campuran yang cukup bagus.
00:05:42Oh, satu halaman lagi yang lupa saya tunjukkan.
00:05:45Halaman produk, yang paling penting.
00:05:47Juga di sini,
00:05:48kita bisa melihat informasi produk dan kemudian menyimpannya jika kita suka untuk pengguna kita.
00:05:52Jadi perhatikan bahwa ada campuran yang cukup bagus antara konten statis dan dinamis di aplikasi ini karena semua fitur yang bergantung pada pengguna.
00:05:59Mari kita lihat juga kodenya, yang ada di sini.
00:06:05Jadi saya menggunakan `app router` di sini,
00:06:07tentu saja,
00:06:07di Next.js 16.
00:06:08Saya punya semua halaman yang berbeda,
00:06:10seperti halaman Tentang,
00:06:11halaman Semua,
00:06:12halaman produk kita.
00:06:13Saya juga punya-- saya menggunakan `feature slicing` di sini untuk menjaga folder aplikasi saya tetap rapi.
00:06:17Saya punya komponen dan kueri yang berbeda yang berkomunikasi dengan database saya menggunakan Prisma.
00:06:23Jadi ya, dan saya sengaja memperlambat semua ini.
00:06:25Itulah mengapa kita memiliki tahap pemuatan yang sangat panjang ini,
00:06:28agar kita bisa lebih mudah melihat apa yang terjadi.
00:06:31Jadi masalah umum yang ingin kami kerjakan di sini yang sebenarnya kami miliki di aplikasi ini adalah `prop drilling`,
00:06:37membuatnya sulit untuk memelihara fitur refactor,
00:06:40akses JavaScript sisi klien,
00:06:41dan kurangnya rendering statis yang menyebabkan biaya server tambahan dan performa terintegrasi.
00:06:47Jadi tujuan demo ini pada dasarnya hanya untuk meningkatkan aplikasi ini dengan beberapa pola cerdas terkait komposisi,
00:06:53caching,
00:06:53dan arsitektur untuk memperbaiki fitur-fitur umum tersebut dan membuatnya lebih cepat,
00:06:58lebih skalabel,
00:06:59dan lebih mudah dipelihara.
00:07:01Jadi mari kita mulai dengan itu.
00:07:02Masalah pertama yang ingin kita perbaiki sebenarnya terkait dengan `prop drilling`.
00:07:05Dan itu ada di sini di halaman.
00:07:10Perhatikan di sini,
00:07:11saya punya variabel `loggedIn` ini di bagian atas.
00:07:15Dan Anda bisa lihat saya meneruskannya ke beberapa komponen.
00:07:17Sebenarnya sudah diteruskan beberapa tingkat ke dalam spanduk pribadi ini.
00:07:20Jadi ini akan menyulitkan untuk menggunakan kembali sesuatu di sini karena kita selalu memiliki dependensi `loggedIn` ini untuk spanduk selamat datang kita.
00:07:28Jadi dengan komponen server,
00:07:29praktik terbaik adalah benar-benar mendorong pengambilan data ke dalam komponen yang menggunakannya dan menyelesaikan `promise` lebih dalam ke dalam pohon.
00:07:37Dan agar ini terotentikasi,
00:07:39selama ini menggunakan `fetch` atau sesuatu seperti `React cache`,
00:07:42kita bisa menduplikasi beberapa panggilan ini,
00:07:44dan kita bisa menggunakannya kembali di mana saja yang kita suka di dalam komponen kita.
00:07:48Jadi itu akan sangat baik untuk digunakan kembali.
00:07:51Jadi sekarang kita bisa memindahkan ini ke bagian yang dipersonalisasi di sini.
00:07:54Dan kita tidak-- tidak akan membutuhkan `prop` ini lagi.
00:07:57Dan cukup letakkan langsung-- aduh-- di sini.
00:08:01Dan kita tidak perlu meneruskan ini lagi.
00:08:04Dan karena kita sekarang memindahkan panggilan asinkron ini ke bagian yang dipersonalisasi,
00:08:07kita tidak lagi memblokir halaman.
00:08:09Kita bisa melanjutkan dan menangguhkan ini hanya dengan `Suspense` sederhana di sini.
00:08:13Dan kita tidak akan membutuhkan `fallback` ini.
00:08:16Untuk spanduk selamat datang,
00:08:19saya kira kita akan melakukan hal yang sama.
00:08:22Tapi mencoba menggunakan-- mendapatkan variabel atau nilai `loggedIn` di sini,
00:08:26itu tidak berfungsi,
00:08:27kan?
00:08:27Karena ini adalah komponen klien.
00:08:29Jadi kita perlu menyelesaikannya dengan cara yang berbeda.
00:08:30Dan kita akan menggunakan pola yang cukup cerdas di sini untuk menyelesaikannya.
00:08:33Kita sebenarnya akan masuk ke `layout` dan membungkus semuanya di sini dengan `auth provider`.
00:08:39Jadi saya akan meletakkan ini di sekitar seluruh aplikasi saya di sini dan mendapatkan variabel `loggedIn` ini di sini.
00:08:45Dan saya jelas tidak ingin memblokir seluruh `root layout` saya.
00:08:48Mari kita lanjutkan dan hapus `await` di sini.
00:08:50Dan cukup teruskan ini sebagai `promise` ke `auth provider` ini.
00:08:55Dan ini bisa saja berisi `promise` itu.
00:08:57Itu bisa saja 'bersantai' di sana sampai kita siap membacanya.
00:09:01Jadi sekarang kita sudah menyiapkan ini.
00:09:03Itu berarti kita sebenarnya bisa melanjutkan dan kita akan menyingkirkan `prop` ini,
00:09:08pertama-tama.
00:09:09Dan kita akan menyingkirkan `prop drilling` yang ini ke `personal banner`.
00:09:12Dan kita akan menyingkirkan `prop drilling` juga di sini atau tanda tangan.
00:09:16Dan sekarang kita bisa menggunakan `auth provider` ini untuk mengambil nilai `loggedIn` ini secara lokal di dalam `personal banner` dengan `useAuth` dengan `provider` yang baru saja kita buat.
00:09:26Dan membacanya dengan `use`.
00:09:28Jadi ini sebenarnya akan berfungsi seperti dalam cara di mana kita perlu menangguhkan ini saat sedang menyelesaikan.
00:09:33Jadi sekarang saya baru saja menempatkan pengambilan data kecil itu di dalam `personal banner`.
00:09:37Dan saya tidak harus meneruskan `prop` itu ke mana-mana.
00:09:40Dan saat ini sedang menyelesaikan,
00:09:41mari kita lanjutkan dan menangguhkan yang ini juga dengan `fallback`.
00:09:44Dan mari kita buat spanduk umum di sini untuk menghindari pergeseran kumulatif yang aneh.
00:09:51Dan akhirnya, singkirkan juga yang ini.
00:09:53Jadi sekarang spanduk selamat datang ini dapat disusun.
00:09:58Ini dapat digunakan kembali.
00:09:59Kita tidak punya `prop` atau dependensi aneh di halaman beranda.
00:10:02Dan karena kita bisa menggunakannya kembali dengan sangat mudah,
00:10:06mari kita lanjutkan dan tambahkan juga ke halaman browser ini di sini,
00:10:10yang akan ada di sini.
00:10:11Dan saya bisa langsung menggunakannya di sini tanpa dependensi apa pun.
00:10:15Jadi melalui pola-pola ini,
00:10:17kita dapat mempertahankan arsitektur komponen yang baik dengan memanfaatkan `React cache`,
00:10:24`React use`,
00:10:25dan membuat komponen kita lebih dapat digunakan dan disusun.
00:10:30Baiklah.
00:10:31Mari kita atasi tantangan umum berikutnya,
00:10:34yaitu JavaScript sisi klien yang berlebihan dan komponen besar dengan banyak tanggung jawab.
00:10:40Sebenarnya, itu juga ada di halaman Semua di sini.
00:10:43Dan lagi, kita harus mengerjakan spanduk selamat datang ini.
00:10:46Saat ini ini adalah komponen klien.
00:10:48Dan alasan mengapa ini adalah komponen klien adalah karena saya memiliki `state dismissed` yang sangat sederhana di sini.
00:10:53Saya bisa mengklik ini.
00:10:54Ini adalah interaksi UI yang bagus.
00:10:56Tidak masalah.
00:10:57Namun,
00:10:57yang tidak begitu baik adalah karena itu,
00:11:00saya mengubah seluruh komponen ini menjadi komponen sisi klien atau komponen klien.
00:11:04Dan saya bahkan menggunakan `swr` untuk mengambil data sisi klien.
00:11:07Saya sekarang punya lapisan API ini di sini.
00:11:08Saya tidak punya `type safety` lagi di data saya.
00:11:11Ya, ini tidak perlu.
00:11:12Dan kita juga melanggar pemisahan kekhawatiran di sini karena kita melibatkan logika UI dengan data.
00:11:18Jadi mari kita lanjutkan dan gunakan pola cerdas lain untuk memperbaikinya.
00:11:21Ini disebut pola donat.
00:11:23Pada dasarnya,
00:11:23yang akan saya lakukan adalah mengekstrak ini ke dalam `wrapper` sisi klien.
00:11:27Jadi mari kita buat komponen baru di sini.
00:11:29Dan mari kita sebut `banner container`.
00:11:32Dan ini akan berisi logika interaktif kita dengan direktif `use client`.
00:11:37Kita bisa membuat tanda tangan.
00:11:38Kita bisa menempelkan semua yang baru saja kita miliki sebelumnya.
00:11:42Dan alih-alih menggunakan spanduk-spanduk ini,
00:11:45saya hanya akan menyisipkan `prop` di sini,
00:11:47yaitu `children`.
00:11:48Jadi inilah mengapa disebut pola donat.
00:11:50Kita hanya membuat logika UI `wrapper` ini di sekitar konten yang dirender server,
00:11:54atau bisa juga konten yang dirender server.
00:11:56Dan kemudian karena kita tidak lagi memiliki dependensi sisi klien ini,
00:11:59kita bisa melanjutkan dan menghapus `use client`.
00:12:01Kita bisa menggunakan fungsi asinkron `isAuth` kita di sini sebagai gantinya.
00:12:06Kita bisa mengubah ini menjadi komponen server asinkron.
00:12:09Kita bahkan bisa mengganti pengambilan data sisi klien dengan pengambilan data sisi server.
00:12:11Jadi izinkan saya langsung mengambil data diskon di sini.
00:12:16Data diskon.
00:12:18Dan cukup manfaatkan model mental reguler kita seperti sebelumnya dengan `type safety`.
00:12:24Dan itu berarti saya juga bisa menghapus lapisan API ini yang tidak ingin saya gunakan.
00:12:29Terakhir,
00:12:29untuk `isLoading`,
00:12:30kita bisa mengekspor spanduk selamat datang baru di sini dengan `banner container` pola donat kita yang berisi konten yang dirender server.
00:12:38Dan itu berarti kita tidak membutuhkan `isLoading` ini lagi.
00:12:40Jadi pada dasarnya kita memfaktorkan ulang seluruh hal ini menjadi komponen server dan mengekstrak titik logika UI.
00:12:46Tapi apa itu?
00:12:48Sepertinya saya punya kesalahan lain.
00:12:51Jadi ini sebenarnya karena Motion.
00:12:53Gunakan Motion.
00:12:54Ini adalah pustaka animasi yang sangat bagus,
00:12:57tetapi membutuhkan direktif `useClient`.
00:12:59Dan lagi,
00:12:59kita tidak perlu membuat ini `useClient` hanya untuk animasi.
00:13:03Kita bisa membuat,
00:13:04lagi,
00:13:05`wrapper` pola donat dan hanya mengekstrak `wrapper` untuk animasi ini.
00:13:10Dan itu berarti kita tidak perlu mengubah apa pun di sini menjadi sisi klien.
00:13:14Dan saya mungkin melewatkan sesuatu di sini.
00:13:17Ya.
00:13:18Itu dia.
00:13:21Jadi sekarang semuanya di sini telah dikonversi ke server.
00:13:23Kita punya interaksi yang sama.
00:13:24Kita masih punya logika interaktif kita di sini,
00:13:27tapi sekarang kita punya satu cara ini untuk mengambil data.
00:13:29Dan kita punya lebih sedikit JS sisi klien.
00:13:31Sebenarnya,
00:13:32saya sendiri menggunakan pola donat ini untuk `UI boundary helper` ini,
00:13:39yang terlihat seperti ini.
00:13:42Anda lihat itu?
00:13:43Jadi ini semacam menunjukkan,
00:13:44lagi,
00:13:45apa yang saya maksud,
00:13:45kan?
00:13:45Dengan pola donat,
00:13:46kita punya komponen klien ini di sekitar komponen server.
00:13:49Saya juga menandai banyak komponen saya yang lain dengan `UI helper` ini di sini.
00:13:53Juga di sini, saya punya lebih banyak komponen server.
00:13:56Mari kita lanjutkan dan tingkatkan itu juga,
00:13:59karena kita sudah cukup mahir sekarang.
00:14:01Mereka ada di `footer`.
00:14:04Kategori-kategori ini-- maksud saya,
00:14:05saya punya komponen bagus ini yang mengambil datanya sendiri.
00:14:08Dan saya hanya ingin menambahkan fitur `showMore` ini,
00:14:11jaga-jaga jika terlalu panjang.
00:14:14Dan dengan pola donat,
00:14:15saya bisa membungkus komponen `showMore` di sini.
00:14:20Dan ini akan berisi logika UI saya.
00:14:23Dan terlihat seperti ini, kan?
00:14:27Cukup keren.
00:14:28Dan ini sekarang berisi logika klien,
00:14:30memungkinkan kita menggunakan `state`.
00:14:33Kita menggunakan `children count` dan `to array` untuk memotong ini.
00:14:36Dan yang keren di sini adalah kedua ini sekarang sepenuhnya komponen yang dapat disusun,
00:14:40dapat digunakan kembali yang bekerja bersama seperti ini.
00:14:42Jadi ini benar-benar keindahan dari pola-pola yang kita pelajari di sini.
00:14:45Anda bisa menggunakan ini untuk apa saja.
00:14:50Saya juga menggunakannya untuk modal ini di sini.
00:14:52Ya,
00:14:52ingat saja ini lain kali Anda mempertimbangkan untuk menambahkan logika klien apa pun ke komponen server Anda.
00:14:59Oke, kita tahu pola donat.
00:15:01Kita tahu cara memanfaatkannya untuk membuat komponen yang dapat disusun ini dan menghindari `plans.js`,
00:15:07jadi kita bisa melanjutkan ke masalah terakhir.
00:15:10Izinkan saya menutup ini lagi.
00:15:13Jadi itu akan terkait dengan kurangnya strategi rendering statis,
00:15:18kan?
00:15:18Melihat output build saya,
00:15:20saya sebenarnya memiliki setiap halaman sebagai halaman dinamis di sini.
00:15:24Jadi itu berarti setiap kali saya memuat sesuatu di sini,
00:15:27ini akan berjalan untuk setiap pengguna.
00:15:29Maaf.
00:15:30Setiap pengguna yang membuka ini akan mendapatkan `loading state` ini.
00:15:33Ini akan membuang-buang biaya server,
00:15:35membuat performa lebih buruk.
00:15:37Dan itu berarti juga bahwa sesuatu di dalam halaman saya menyebabkan rendering dinamis atau memaksa rendering dinamis untuk semua halaman saya.
00:15:45Sebenarnya, itu ada di dalam `root layout` saya.
00:15:49Saya tidak tahu apakah Anda mengalaminya.
00:15:51Itu ada di sini.
00:15:53Di `header` saya, saya punya profil pengguna ini.
00:15:57Dan ini,
00:15:57tentu saja,
00:15:58menggunakan `cookie` untuk mendapatkan pengguna saat ini,
00:16:00dan itu berarti semua hal lainnya juga dirender secara dinamis.
00:16:02Karena lagi, halaman bisa dinamis atau statis, kan?
00:16:06Ini adalah masalah yang cukup umum dan sesuatu yang telah diselesaikan sebelumnya di versi Next sebelumnya,
00:16:11jadi mari kita lihat apa yang bisa kita lakukan.
00:16:13Satu hal yang bisa kita lakukan adalah membuat `route group` dan membagi aplikasi kita menjadi bagian statis dan dinamis yang akan memungkinkan saya mengekstrak halaman Tentang saya.
00:16:23Saya bisa merender ini secara statis.
00:16:25Tidak masalah untuk beberapa aplikasi,
00:16:27tetapi dalam kasus saya,
00:16:28halaman penting adalah halaman produk,
00:16:30dan ini masih dinamis,
00:16:31jadi tidak terlalu membantu.
00:16:33Bagaimana dengan strategi ini?
00:16:35Jadi di sini saya membuat `request context param` ini yang mengkodekan `state` tertentu ke dalam URL saya,
00:16:40dan kemudian saya bisa menggunakan `generate static params` untuk menghasilkan semua varian halaman saya yang berbeda.
00:16:46Itu sebenarnya,
00:16:47dikombinasikan dengan pengambilan data pengguna sisi klien,
00:16:50akan memungkinkan saya untuk mendapatkan ini di-cache di halaman produk saya.
00:16:54Jelas pola yang layak.
00:16:55Ini direkomendasikan oleh Vercel Flags SDK yang disebut pola `precompute`,
00:17:00saya kira.
00:17:00Tapi ini sangat kompleks,
00:17:01dan saya punya banyak cara untuk mengambil data.
00:17:04Dan sebenarnya,
00:17:04saya tidak ingin menulis ulang seluruh aplikasi saya menjadi seperti ini.
00:17:07Jadi bagaimana jika kita tidak perlu melakukan semua solusi itu?
00:17:10Bagaimana jika ada cara yang lebih sederhana?
00:17:12Nah, ada.
00:17:14Mari kita kembali ke aplikasi kita lagi.
00:17:17Jadi kita sebenarnya bisa pergi ke `next config` dan cukup mengaktifkan `cache components`.
00:17:23Oh, bagus.
00:17:25Oke,
00:17:25dan apa yang dilakukan ini,
00:17:27seperti yang Anda tahu dari `keynote`,
00:17:29sebenarnya akan membuat semua panggilan asinkron kita menjadi `request time` atau dinamis.
00:17:34Dan itu juga akan memberi kita kesalahan setiap kali kita memiliki panggilan asinkron yang tidak ditangguhkan,
00:17:40dan itu akan memberi kita direktif `use cache` ini yang dapat kita gunakan untuk melakukan cache secara granular baik halaman,
00:17:47fungsi,
00:17:47atau komponen.
00:17:48Jadi ya, mari kita lanjutkan dan manfaatkan ini.
00:17:51Kita bisa mulai dengan halaman beranda di sini.
00:17:55Mari kita lihat.
00:17:56Jadi lagi,
00:17:56saya punya campuran konten statis dan dinamis ini.
00:17:59Saya punya spanduk selamat datang untuk saya,
00:18:01sesuatu untuk Anda juga untuk saya.
00:18:03Mari kita lihat itu dengan `UI helper` ini lagi.
00:18:06Jadi misalnya,
00:18:07spanduk dirender secara dinamis dengan ini di sini.
00:18:10Sedangkan saya menandai ini sebagai `hybrid rendering` karena `hero`,
00:18:15itu mengambil hal asinkron ini dan berjalan cukup lambat.
00:18:18Tapi itu tidak bergantung pada jenis data pengguna atau API dinamis apa pun.
00:18:21Jadi itu berarti bahwa semua yang dirender secara hibrida di sini sebenarnya dapat digunakan kembali di seluruh permintaan dan di seluruh pengguna.
00:18:27Dan kita bisa menggunakan direktif `use cache` pada itu.
00:18:30Jadi mari kita tambahkan direktif `use cache` di sini dan tandai ini sebagai di-cache.
00:18:35Dan itu akan memungkinkan saya untuk-- setiap kali saya memuat ulang halaman ini-- saya tidak menyimpan ini.
00:18:43Itu dia.
00:18:44Ini tidak akan memuat ulang bagian ini karena sudah di-cache.
00:18:47Sekarang statis, kan?
00:18:49Dan ada juga API terkait lainnya seperti `cache tag` untuk memungkinkan saya mengetik ini atau memvalidasi entri cache tertentu secara granular atau menentukan periode pengungkapan saya.
00:19:01Tapi untuk demo ini, mari kita fokus pada direktif biasa.
00:19:05Sekarang setelah saya memiliki direktif `use cache` ini,
00:19:07saya sebenarnya bisa menghapus `suspense boundary` saya di sekitar `hero` ini.
00:19:10Dan itu berarti-- nah,
00:19:12apa yang akan dilakukan ini adalah `partial prerendering` sebenarnya bisa melanjutkan dan menyertakan ini dalam `shell` yang dirender sebelumnya secara statis sehingga `hero` ini akan,
00:19:21dalam kasus ini,
00:19:21menjadi bagian dari output build saya.
00:19:23Mari kita lakukan hal yang sama untuk semua hal lain di halaman ini yang dapat dibagikan.
00:19:28Misalnya, saya punya kategori fitur ini di sini.
00:19:31Mari kita lanjutkan dan lakukan hal yang sama di sana.
00:19:33Dan tambahkan direktif `use cache` dan tandai ini sebagai di-cache.
00:19:37Seperti itu.
00:19:39Dan kita bisa menghapus `suspense boundary`.
00:19:40Kita tidak akan membutuhkan ini lagi.
00:19:43Sama untuk produk unggulan.
00:19:44Mari kita tambahkan `use cache` dan tandai ini sebagai di-cache.
00:19:48Ups.
00:19:50Dan kemudian hapus `suspense boundary`.
00:19:52Jadi perhatikan berapa banyak kompleksitas yang baru saja bisa saya hapus di sini.
00:19:55Saya tidak perlu khawatir tentang `skeleton` saya,
00:19:57`cumulative layout shift` yang saya lakukan sebelumnya.
00:20:00Dan halaman tidak lagi-- atau kita tidak lagi memiliki batasan statis versus dinamis tingkat halaman ini.
00:20:07Jadi sekarang ketika saya memuat halaman ini,
00:20:10Anda akan melihat semuanya di sini di-cache kecuali untuk konten yang benar-benar spesifik pengguna ini.
00:20:16Benar.
00:20:18Jadi itu cukup keren.
00:20:19Mari kita pergi ke halaman Jelajahi dan lakukan hal yang sama di sana.
00:20:24Ya.
00:20:25Saya sudah menandai semua batas saya di sini agar Anda dapat dengan mudah memahami apa yang terjadi.
00:20:29Dan saya ingin setidaknya melakukan cache kategori-kategori ini.
00:20:33Tapi sepertinya saya mendapatkan kesalahan.
00:20:37Mungkin Anda mengenali ini.
00:20:38Jadi itu berarti saya punya `blocking route`.
00:20:40Dan saya tidak menggunakan `suspense boundary` padahal seharusnya.
00:20:43Menyegarkan ini, memang benar, ya?
00:20:46Ini sangat lambat.
00:20:47Dan itu menyebabkan masalah performa dan UX yang buruk.
00:20:50Jadi ini bagus.
00:20:51`Use cache` atau `cache components` membantu saya mengidentifikasi `blocking route` saya.
00:20:55Mari kita lihat apa yang sebenarnya terjadi di dalamnya.
00:20:57Jadi ini masalahnya, kan?
00:20:59Saya mengambil kategori-kategori ini di tingkat atas dan saya tidak punya `suspense boundary` di atasnya.
00:21:03Pada dasarnya, kita perlu membuat pilihan.
00:21:05Entah kita menambahkan `suspense boundary` di atas atau kita memilih untuk melakukan caching.
00:21:09Mari kita lakukan hal sederhana dulu dan cukup tambahkan `loading.tsx` di sini.
00:21:12Dan mari kita tambahkan halaman pemuatan di sini,
00:21:17beberapa UI `skeleton` yang bagus.
00:21:21Itu cukup bagus.
00:21:21Itu menyelesaikan kesalahan,
00:21:22tapi saya tidak punya apa pun yang berguna terjadi di halaman ini saat saya menunggu.
00:21:25Saya bahkan tidak bisa mencari.
00:21:27Jadi dengan `cache components`,
00:21:29dinamis itu seperti-- atau statis versus dinamis itu seperti sebuah skala.
00:21:33Dan terserah kita untuk memutuskan seberapa banyak statis yang kita inginkan di halaman kita.
00:21:37Jadi mari kita geser halaman ini lebih ke arah statis dan cukup hapus `loading.tsx` ini lagi.
00:21:43Dan kemudian manfaatkan pola-pola yang kita pelajari sebelumnya untuk mendorong pengambilan data ini ke dalam komponen dan menempatkannya bersama dengan UI.
00:21:50Jadi pindahkan ini ke `responsive category filters` saya di sini.
00:21:54Saya punya dua karena desain responsif.
00:21:57Saya sebenarnya bisa melanjutkan dan menambahkannya di sini.
00:22:01Ups.
00:22:03Dan impor ini.
00:22:05Saya tidak butuh `prompt` ini lagi.
00:22:06Sebenarnya, komponen saya menjadi lebih dapat disusun.
00:22:09Dan alih-alih menangguhkannya,
00:22:11mari kita tambahkan direktif `use cache`.
00:22:14Dan itu seharusnya cukup.
00:22:16Jadi perhatikan bagaimana saya dipaksa untuk lebih memikirkan di mana saya menyelesaikan `promise` saya dan sebenarnya meningkatkan arsitektur komponen saya melalui ini.
00:22:24Saya tidak perlu menangguhkan ini.
00:22:25Ini hanya akan disertakan dalam `static shell` di sini.
00:22:28Daftar produk, biarkan saya tetap segar.
00:22:35Jadi saya bisa memuat ulang itu setiap saat.
00:22:37Sedangkan kategori di bagian bawah,
00:22:39saya juga ingin melakukan cache ini.
00:22:41Jadi mari kita lanjutkan dan pergi ke `footer`.
00:22:44Dan karena saya menggunakan pola donat di sini,
00:22:47ini sebenarnya bisa di-cache meskipun berada di dalam bagian UI yang interaktif ini.
00:22:54Jadi ini tidak masalah sama sekali.
00:22:55Jadi pola itu tidak hanya bagus untuk komposisi,
00:22:57tetapi juga untuk caching.
00:22:58Saya pikir saya punya satu kesalahan lagi di sana.
00:23:03Mari kita lihat apa itu.
00:23:04Masih ada kesalahan ini.
00:23:08Ini sebenarnya karena `search frames` ini.
00:23:10`Search frames`, seperti yang kita tahu, adalah API dinamis.
00:23:12Saya tidak bisa melakukan cache ini.
00:23:13Tapi saya bisa menyelesaikannya lebih dalam untuk mengungkapkan lebih banyak UI saya dan membuatnya statis.
00:23:18Jadi mari kita lanjutkan dan pindahkan ini ke bawah,
00:23:21teruskan sebagai `promise` ke `product list`.
00:23:24Kita akan membuat ini bertipe `promise` di sini,
00:23:29seperti itu.
00:23:30Mari kita selesaikan di dalam `product list`,
00:23:33gunakan `resolved search parameters` di sini dan di sini.
00:23:36Dan karena ini ditangguhkan di sini,
00:23:38kesalahannya akan hilang.
00:23:40Jadi memuat ulang ini,
00:23:41satu-satunya hal yang memuat ulang di sini hanyalah bagian yang saya pilih secara spesifik untuk menjadi dinamis.
00:23:48Semua yang lain bisa di-cache.
00:23:49Dan itu berarti saya bisa berinteraksi dengan spanduk saya atau bahkan mencari karena bagian itu sudah dirender sebelumnya.
00:23:57Baiklah,
00:23:57mari kita lakukan halaman terakhir di sini,
00:24:01yaitu halaman produk,
00:24:02yang paling sulit dan paling penting.
00:24:05Ini sangat buruk sekarang.
00:24:08Ini sangat penting untuk platform e-commerce, tampaknya.
00:24:11Baiklah, mari kita lanjutkan dan perbaiki yang itu juga.
00:24:15Jadi di sini saya punya halaman produk ini.
00:24:18Mari kita mulai melakukan cache hanya konten yang dapat digunakan kembali di sini,
00:24:22misalnya,
00:24:22produk itu sendiri.
00:24:23Dan cukup tambahkan `use cache` di sini dan tandai ini sebagai di-cache.
00:24:27Itu seharusnya baik-baik saja.
00:24:28Itu berarti kita bisa menghapus `suspense boundary` di sini.
00:24:33Baiklah,
00:24:33dan ini tidak lagi memuat ulang pada setiap permintaan di sini,
00:24:37kan?
00:24:38Untuk detail produk, mari kita lakukan hal yang sama.
00:24:40Mari kita tambahkan `use cache`.
00:24:41Mari kita tandai sebagai di-cache dan lihat apakah itu juga akan berfungsi.
00:24:47Tidak berhasil.
00:24:48Sebenarnya, ini adalah kesalahan yang berbeda.
00:24:50Ini memberi tahu saya bahwa saya mencoba menggunakan API dinamis di dalam segmen yang di-cache ini.
00:24:54Dan itu benar.
00:24:54Saya menggunakan tombol Simpan Produk, kan?
00:24:56Itu memungkinkan saya untuk mengklik dan mengubah `saved state`.
00:25:00Jadi menurut Anda apa yang bisa kita lakukan dengan ini?
00:25:03Kita bisa menggunakan pola donat lagi.
00:25:06Sebenarnya,
00:25:06kita juga bisa menyisipkan segmen dinamis ke dalam segmen cache.
00:25:10Jadi kita menyisipkannya seperti sebelumnya,
00:25:11tetapi dengan cache.
00:25:12Jadi ini cukup keren.
00:25:14Mari kita lanjutkan dan tambahkan `children` di sini seperti itu.
00:25:19Dan ini akan menghilangkan kesalahan.
00:25:21Dan saya bisa membungkus ini di sekitar satu segmen dinamis halaman saya di sini,
00:25:26menghapus `suspense boundary`,
00:25:28dan menambahkan UI `bookmark` yang sangat kecil untuk satu bagian dinamis halaman itu.
00:25:34Dan mari kita lihat bagaimana tampilannya sekarang.
00:25:40Jadi perhatikan bagaimana hampir seluruh UI tersedia,
00:25:43tetapi saya punya satu bagian kecil yang dinamis,
00:25:46dan itu tidak masalah.
00:25:47Semua yang lain masih ada.
00:25:48Dan mari kita biarkan ulasan tetap dinamis karena kita bisa menjaganya tetap segar.
00:25:53Masih ada satu kesalahan lagi.
00:25:54Mari kita cepat atasi itu.
00:25:56Lagi, ini adalah `params`.
00:25:58Saya mendapatkan bantuan bahwa saya perlu membuat pilihan,
00:26:01entah menambahkan `loading fallback` atau melakukan cache ini.
00:26:04Mari kita gunakan `generate static params` dalam kasus ini.
00:26:07Agak tergantung pada kasus penggunaan Anda dan set data Anda.
00:26:10Tapi untuk kasus ini,
00:26:11saya hanya akan menambahkan beberapa halaman yang sudah dirender sebelumnya dan kemudian cukup melakukan cache sisanya saat dibuat oleh pengguna.
00:26:17Dan ini akan menghilangkan kesalahan saya di sini.
00:26:20Jadi saya pikir saya sebenarnya sudah selesai dengan refactor saya.
00:26:22Mari kita lanjutkan dan lihat versi yang sudah di-deploy dan lihat seperti apa tampilannya.
00:26:26Jadi saya baru saja mendeploy ini di Vercel.
00:26:27Dan ingat,
00:26:29saya sengaja memperlambat banyak pengambilan data di sini.
00:26:35Dan tetap saja,
00:26:36ketika saya memuat halaman ini pada awalnya,
00:26:39semuanya sudah tersedia.
00:26:40Satu-satunya hal di sini hanyalah beberapa segmen dinamis seperti diskon dan untuk Anda.
00:26:46Sama dengan `browse all`.
00:26:47Semua UI sudah tersedia.
00:26:50Dan untuk produk itu sendiri, rasanya instan.
00:26:54Dan ingat,
00:26:55lagi,
00:26:55bahwa semua segmen cache ini akan disertakan dengan `static shell` dengan `partial pre-rendering`.
00:27:00Dan itu bisa di-prefetch menggunakan `prefetching` yang ditingkatkan di `client router` Next 16 yang baru.
00:27:05Jadi itu berarti setiap navigasi hanya-- rasanya sangat cepat,
00:27:09kan?
00:27:09Baiklah,
00:27:10untuk meringkas,
00:27:11dengan `cache components`,
00:27:14tidak ada lagi statis versus dinamis.
00:27:17Dan kita tidak perlu menghindari API dinamis atau mengkompromikan konten dinamis.
00:27:28Dan kita bisa melewati `hack` dan solusi kompleks ini menggunakan beberapa strategi pengambilan data hanya untuk satu-- `cache hit` ini,
00:27:36seperti yang saya tunjukkan.
00:27:37Jadi di Next.js modern,
00:27:38dinamis versus statis adalah sebuah skala.
00:27:40Dan kita memutuskan seberapa banyak statis yang kita inginkan di aplikasi kita.
00:27:43Dan selama kita mengikuti pola-pola tertentu,
00:27:45kita bisa memiliki satu model mental,
00:27:47yang performan,
00:27:48dapat disusun,
00:27:49dan skalabel secara default.
00:27:50Jadi mari kita kembali ke slide.
00:27:53Jadi jika Anda belum-- kita belum terkesan dengan kecepatan itu,
00:27:55ini adalah skor Lighthouse.
00:27:56Jadi saya mengumpulkan beberapa data lapangan dengan Vercel Speed Insights.
00:28:00Jadi kita punya skor 100 di semua halaman terpenting,
00:28:02halaman beranda,
00:28:03halaman produk,
00:28:04dan daftar produk,
00:28:05meskipun halaman-halaman tersebut sangat dinamis.
00:28:08Jadi mari kita akhirnya meringkas pola-pola yang akan memastikan skalabilitas dan performa di aplikasi Next.js dan memungkinkan kita memanfaatkan inovasi terbaru serta mendapatkan skor seperti ini.
00:28:18Jadi pertama,
00:28:19kita bisa menyempurnakan arsitektur kita dengan menyelesaikan `promise` jauh di dalam pohon komponen dan mengambil data secara lokal di dalam komponen menggunakan `React Cache` untuk menduplikasi pekerjaan.
00:28:28Kita bisa menghindari penerusan `prop` yang berlebihan ke komponen klien dengan menggunakan `context providers` yang dikombinasikan dengan `React Use`.
00:28:35Kedua,
00:28:35kita bisa menyusun komponen klien yang melayani menggunakan pola donat untuk mengurangi JavaScript sisi klien,
00:28:40menjaga pemisahan kekhawatiran yang jelas,
00:28:42dan memungkinkan penggunaan kembali komponen.
00:28:43Dan pola ini akan lebih lanjut memungkinkan kita untuk melakukan cache komponen server kita yang disusun nanti.
00:28:50Dan terakhir,
00:28:50kita bisa melakukan cache dan pra-render dengan `use cache` baik berdasarkan halaman,
00:28:54komponen,
00:28:54atau fungsi untuk menghilangkan pemrosesan yang berlebihan,
00:28:56meningkatkan performa dan SEO,
00:28:58dan membiarkan `partial pre-rendering` merender segmen-segmen aplikasi ini secara statis.
00:29:01Dan jika konten kita benar-benar dinamis,
00:29:03kita bisa menangguhkannya dengan `loading fallback` yang sesuai.
00:29:07Dan ingat bahwa semua ini saling terhubung.
00:29:09Jadi semakin baik arsitektur Anda,
00:29:10semakin mudah untuk menyusun,
00:29:11dan semakin mudah untuk melakukan cache dan pra-render dengan hasil terbaik.
00:29:15Misalnya,
00:29:15menyelesaikan API dinamis jauh di dalam pohon akan memungkinkan Anda membuat `static shell` yang dirender sebagian lebih besar.
00:29:22Dan dengan itu,
00:29:22ini adalah `repo` dari versi aplikasi yang sudah selesai.
00:29:25Ada begitu banyak hal yang bahkan tidak saya tunjukkan di sana yang bisa Anda lihat.
00:29:29Dan Anda bisa memindai kode QR untuk menemukan media sosial saya di sana bersama dengan `repo` jika Anda tidak ingin mengambil gambar dan mengetiknya sendiri.
00:29:36Jadi ya, itu saja dari saya.
00:29:37Terima kasih Next.js Conf telah mengundang saya di sini.
00:29:39[MUSIK BERMAIN]