Bikin Aplikasi ReactJS Makin Ngebut Ternyata Gini Caranya (Tips Buat Kamu)
Pernah nggak sih ngerasain buka aplikasi ReactJS terus loadingnya lama banget? Atau pas lagi scroll-scroll, kok rasanya agak nge-lag gitu? Nah, itu tandanya aplikasi kamu butuh sentuhan "tune-up" di bagian performanya. Di dunia pengembangan web modern, kecepatan itu bukan cuma soal kenyamanan user, tapi juga bisa ngaruh ke SEO, user retention, bahkan konversi. Aplikasi yang ngebut bikin user betah, nggak gampang kabur, dan pastinya ninggalin kesan positif.
ReactJS itu framework yang keren banget buat bikin UI yang interaktif dan kompleks. Tapi karena saking fleksibelnya, kalau nggak hati-hati, kita bisa aja nggak sengaja bikin aplikasi yang boros sumber daya dan akhirnya lemot. Jangan khawatir! Banyak banget cara buat bikin aplikasi React kamu makin ngebut. Tips-tips ini relevan, aplikatif, dan pastinya update buat kondisi pengembangan React sekarang. Yuk, kita bongkar satu per satu.
1. Pake React.memo
Buat Hindari Re-render yang Nggak Perlu
Ini salah satu trik paling dasar tapi powerful di React functional components. Pernah liat komponen anak (child component) ikut ke-render ulang, padahal props atau statenya nggak berubah sama sekali? Itu pemborosan sumber daya namanya.
React.memo
adalah Higher-Order Component (HOC) yang bisa kamu pake buat "mengafal" (memoize) komponen fungsional. Maksudnya gini, React bakal "inget" hasil render komponen itu. Kalau props yang diterimanya nggak berubah dari render sebelumnya, React nggak akan nge-render ulang komponen itu. Dia cuma pake hasil yang udah diinget tadi.
Contoh simplenya:
javascript
import React from 'react';// Komponen ini cuma nerima prop 'nama'
const KomponenAnak = ({ nama }) => {
console.log('Komponen Anak sedang di-render'); // Ini bakal muncul tiap kali render
return (
Halo, {nama}!
);
};// Kalau parentnya re-render tapi prop 'nama' nggak berubah,
// KomponenAnak ini tetap ikut re-render.// Sekarang kita bungkus pake React.memo
const KomponenAnakMemoized = React.memo(({ nama }) => {
console.log('Komponen Anak Memoized sedang di-render'); // Ini cuma muncul kalau prop 'nama' berubah
return (
Halo, {nama}!
);
});
Dengan pake React.memo
, KomponenAnakMemoized
cuma akan re-render kalau prop nama
beneran berubah. Kalau komponen parentnya re-render tapi ngasih prop nama
yang nilainya sama, React bakal skip proses rendering KomponenAnakMemoized
.
Kapan Pake React.memo
?
- Komponen fungsional.
- Komponen yang sering dipake ulang atau berada di dalam list yang panjang.
- Komponen yang proses renderingnya lumayan berat.
- Komponen yang jarang props-nya berubah.
Hati-hati: Kalau props kamu itu objek atau array, React.memo melakukan perbandingan "shallow" (dangkal). Artinya, dia cuma ngecek apakah referensi objek/array itu sama, bukan isi di dalamnya. Kalau kamu selalu bikin objek/array baru di parent (misalnya props={{ data: [...oldData] }}
), meskipun isinya sama, React.memo bakal nganggep props-nya berubah dan tetap re-render. Di sinilah useMemo
dan useCallback
bakal berguna.
2. Manfaatin useMemo
dan useCallback
Buat Memoize Nilai dan Fungsi
Nah, nyambung dari React.memo
, ada hook useMemo
dan useCallback
. Keduanya juga buat memoization, tapi sasarannya beda.
useMemo
: Buat memoize nilai (value). Berguna banget kalau kamu punya kalkulasi yang lumayan kompleks atau bikin objek/array baru di dalam komponen yang di-render tiap saat. Daripada ngitung ulang atau bikin objek/array baru tiap kali render, useMemo
bisa "nginget" hasil kalkulasi atau objek/array tersebut. React bakal cuma ngitung ulang atau bikin ulang kalau ada dependency* (variabel atau state yang dipake di dalam kalkulasi/pembuatan objek) yang berubah.
Contoh:
javascript
import React, { useMemo } from 'react';const KomponenParent = ({ data }) => {
// Misalnya data ini array besar, dan kita butuh ngitung jumlah item aktif
const activeItemCount = useMemo(() => {
console.log('Menghitung item aktif...'); // Ini cuma muncul kalau 'data' berubah
return data.filter(item => item.isActive).length;
}, [data]); // Dependency array: hitung ulang kalau 'data' berubahreturn (
Jumlah item aktif: {activeItemCount}
{/ Komponen lain yang mungkin re-render karena state atau props lain /}
);
};
Tanpa useMemo
, data.filter(...).length
bakal dihitung ulang tiap kali KomponenParent
re-render, meskipun prop data
nggak berubah. Dengan useMemo
dan dependency [data]
, kalkulasi ini cuma jalan kalau referensi array data
berubah.
useCallback
: Buat memoize fungsi (function). Ini penting banget kalau kamu ngasih fungsi sebagai prop ke komponen anak yang di-memoize (pake React.memo
). Ingat yang tadi, kalau props objek/array/fungsi itu dibuat baru tiap render di parent, React.memo
akan tetap nganggep props-nya berubah. Nah, fungsi itu juga termasuk objek. Tiap kali parent re-render, fungsi baru bakal dibuat. useCallback
mencegah hal ini. Dia bakal "nginget" referensi fungsi tersebut dan hanya bikin ulang kalau ada dependency* yang berubah.
Contoh:
javascript
import React, { useState, useCallback, useMemo } from 'react';
import React from 'react'; // Assuming KomponenAnakMemoized is imported from example 1const KomponenParent = () => {
const [count, setCount] = useState(0);
const [name, setName] = useState('Budi');// Kalau ini nggak pake useCallback, KomponenAnakMemoized bakal re-render
// tiap kali state 'count' berubah di parent, meskipun prop 'onButtonClick'
// secara logika sama, tapi referensinya beda tiap render.
const handleButtonClick = useCallback(() => {
setCount(count + 1);
}, [count]); // Dependency array: bikin fungsi baru kalau 'count' berubah// Contoh lain: passing objek sebagai prop ke komponen anak yang di memoize
// const userData = useMemo(() => ({ name: 'Adi', age: 25 }), []); // Objek ini cuma dibuat sekali karena dependency kosongreturn (
Count: {count}
setCount(count + 1)}>Tambah Count{/ Sekarang KomponenAnakMemoized nggak akan re-render kalau cuma state 'count' berubah /}
);
};// Tambahkan prop onButtonClick ke KomponenAnakMemoized (dari contoh 1)
const KomponenAnakMemoized = React.memo(({ nama, onButtonClick }) => {
console.log('Komponen Anak Memoized sedang di-render');
// Mungkin di sini ada button yang panggil onButtonClick
return (
Halo, {nama}!
Klik Aku
);
});
Dengan useCallback
, fungsi handleButtonClick
hanya akan dibuat ulang kalau state count
berubah. Kalau state lain di parent (misalnya name
) berubah, handleButtonClick
tetap pake referensi fungsi yang lama, sehingga KomponenAnakMemoized
yang menerima fungsi ini sebagai prop (dan dibungkus React.memo
) tidak ikut re-render yang tidak perlu.
Kapan Pake useMemo
dan useCallback
?
- Kamu passing objek, array, atau fungsi sebagai props ke komponen anak yang udah di-memoize (
React.memo
). - Ada kalkulasi berat yang sering diulang tiap render.
- Kamu butuh referensi yang stabil untuk fungsi, misalnya buat dependency di hook lain seperti
useEffect
,useMemo
, atauuseCallback
lainnya.
Hati-hati: Jangan overuse useMemo
dan useCallback
. Memoization itu sendiri ada biayanya (memori dan waktu ngecek dependency). Kalau kalkulasinya atau fungsinya simpel banget, biaya memoizationnya bisa lebih mahal daripada re-calculate atau bikin ulang fungsi. Profiling adalah kunci buat tau kapan beneran butuh.
3. Implementasi Lazy Loading dan Code Splitting
Bayangin website kamu itu kayak toko buku gede banget. Kalau tiap ada pengunjung dateng, semua buku (termasuk yang ada di gudang paling belakang) harus diangkat ke depan pintu sebelum toko dibuka, pasti lama banget kan? Mending yang dibawa ke depan itu buku-buku yang ada di display awal aja, nanti kalau pengunjung butuh buku lain baru diambilin dari rak yang relevan.
Konsep ini mirip sama lazy loading (atau code splitting) di React. Secara default, saat kamu build aplikasi React, semua kode komponen, library, CSS, dll. digabung jadi satu atau beberapa file besar (bundle). Browser harus download dan parsing semua file ini di awal, meskipun user cuma liat halaman depan. Ini bikin initial load time jadi lama.
Code splitting memecah bundle besar tadi jadi potongan-potongan kecil. Lazy loading (dibantu sama React.lazy
dan Suspense
) bikin browser cuma nge-load kode komponen tertentu saat dibutuhkan, biasanya pas user navigasi ke halaman atau bagian aplikasi yang pake komponen itu.
javascript
import React, { Suspense } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; // Contoh pake React Router// Ini komponen yang akan di-lazy load
const Beranda = React.lazy(() => import('./pages/Beranda'));
const TentangKami = React.lazy(() => import('./pages/TentangKami'));
const Kontak = React.lazy(() => import('./pages/Kontak'));
Dengan cara ini, kode untuk komponen TentangKami
dan Kontak
nggak bakal di-load pas awal buka aplikasi di halaman /
. Kodenya baru di-load pas user navigasi ke /tentang
atau /kontak
. Ini bikin waktu loading awal halaman beranda jadi jauh lebih cepat.
Kapan Pake Lazy Loading?
- Untuk rute-rute (halaman) yang berbeda.
- Untuk komponen yang muncul berdasarkan interaksi user (misalnya modal, tab yang jarang dibuka).
- Untuk library eksternal yang hanya dipakai di bagian tertentu aplikasi.
Ini cara paling efektif buat mengurangi ukuran bundle awal yang harus di-download browser.
4. Optimasi List yang Panjang Pakai Virtualisasi
Kalau kamu punya list data yang super panjang (misalnya ribuan atau puluhan ribu item) dan kamu render semuanya sekaligus pake map
, browser kamu bakal teriak. Kenapa? Karena dia harus bikin, render, dan manage ribuan elemen DOM di halaman. Ini boros memori dan bikin scrolling jadi nggak mulus.
Solusinya? Virtualisasi list. Konsepnya mirip kayak lazy loading, tapi buat elemen list. Browser cuma render elemen list yang kelihatan di viewport user. Pas user scroll, elemen di luar viewport di-destroy dan elemen baru yang masuk viewport di-render.
Ada beberapa library populer buat ini, contohnya react-window
dan react-virtualized
.
javascript
import { FixedSizeList } from 'react-window';const data = Array.from({ length: 10000 }).map((_, index) => ({
id: index,
text: Item Nomor ${index},
}));const Row = ({ index, style }) => (
{data[index].text}
);
Di contoh ini, meskipun datanya ada 10.000, FixedSizeList
cuma akan render item-item yang muat di dalam area setinggi 400px. Saat user scroll, item di luar area itu bakal di-unmount dan item baru di-mount. Hasilnya, scrolling jadi super lancar, meskipun datanya bejibun.
Kapan Pake Virtualisasi List?
- Saat kamu render list yang jumlah itemnya bisa mencapai ratusan atau ribuan.
- Saat scrolling list terasa lambat atau nge-lag.
5. Optimasi Pengambilan Data (Data Fetching)
Proses ngambil data dari backend juga bisa jadi bottleneck performa. Beberapa hal yang bisa kamu lakuin:
- Hindari Fetching Data yang Redundan: Jangan request data yang sama berkali-kali di komponen yang berbeda atau saat re-render kalau datanya belum berubah. Pake library state management yang punya fitur caching data (kayak React Query, SWR, Apollo Client) atau implementasi caching sederhana sendiri. Hook seperti
useSWR
atauuseQuery
dari React Query sangat membantu buat ngelola state fetching dan caching secara otomatis. - Fetch Data Secukupnya: Jangan minta semua data kalau cuma butuh sebagian. Gunakan parameter query di API backend buat filter, pagination, atau cuma minta field yang diperlukan.
- Fetch Data di Tempat yang Tepat: Biasanya data di-fetch di hook
useEffect
atau di event handler. Pastikan kamu punya dependency array yang bener diuseEffect
biar nggak fetching ulang setiap kali ada re-render yang nggak berhubungan. - Parallel or Sequential Fetching: Tergantung kebutuhan, pertimbangkan apakah beberapa request bisa dijalankan paralel atau harus berurutan. Parallel fetching biasanya lebih cepat kalau requestnya nggak saling bergantung.
6. Perbaiki State Management yang Nggak Efisien
Cara kamu ngelola state di aplikasi juga ngaruh ke performa. Beberapa tips:
- State Colocation: Simpen state sedekat mungkin dengan komponen yang make state itu. Nggak semua state harus ditaro di global state management (Redux, Zustand, Context API di level teratas). Mindahin state yang cuma dipake di satu atau beberapa komponen ke level komponen itu sendiri (
useState
) bisa ngurangin jumlah komponen yang re-render saat state itu berubah. - Hindari Update State yang Berlebihan: Kalau kamu update state berkali-kali dalam satu event loop, React bakal nyoba nge-batch update tersebut. Tapi kalau kamu pake state management yang nggak efisien atau update state secara nggak sinkron, ini bisa micu re-render berkali-kali.
Pake Selector di State Management (Kalau Pake Redux/Zustand): Kalau kamu pake Redux atau Zustand, gunain selector buat ngambil cuma data yang benar-benar dibutuhkan* dari store. Library seperti reselect
(untuk Redux) atau fitur selector bawaan Zustand bisa membantu memoize hasil selector, jadi komponen cuma re-render kalau data yang diambil selector itu beneran berubah, bukan kalau ada data lain di store yang berubah.
7. Gunakan Profiler di React DevTools
Kamu nggak bakal bisa optimasi sesuatu kalau nggak tau apa yang bikin lambat. React DevTools punya tab "Profiler" yang super ngebantu. Kamu bisa merekam proses rendering aplikasi saat berinteraksi, dan profiler bakal nunjukkin berapa lama waktu yang dihabiskan tiap komponen buat render.
Di profiler, kamu bisa liat:
- Komponen mana yang paling sering re-render.
- Berapa lama waktu render tiap komponen.
- Kenapa komponen itu re-render (perubahan props, state, context, atau karena parentnya re-render).
Ini alat yang powerful banget buat identifikasi bottleneck performa. Jangan ngira-ngira aja, profil aplikasi kamu!
8. Optimasi Proses Build (Production Build)
Ini langkah yang sering dilupakan tapi penting banget. Pas mau deploy aplikasi ke production, PASTIKAN kamu jalanin build proses dalam mode production.
- Mode Production: Build tools seperti Create React App, Next.js, Vite, dll., otomatis ngelakuin ini. Mode production ngaktifin optimasi seperti minifikasi kode (ngurangin ukuran file dengan ngapus spasi, komentar, ganti nama variabel jadi pendek), tree shaking (ngapus kode yang nggak kepake), dan optimasi lainnya.
- Minifikasi CSS dan JavaScript: Pastiin CSS dan JavaScript kamu juga diminifikasi.
- Optimalisasi Gambar: Gambar sering jadi penyebab website lemot. Kompres gambar tanpa ngurangin kualitas terlalu banyak, pake format yang efisien (WebP), dan pertimbangkan responsive images (
srcset
). - Compression (Gzip/Brotli): Pastiin server kamu ngaktifin kompresi (Gzip atau Brotli) buat file statis biar ukuran file yang dikirim ke browser lebih kecil.
Perbedaan performa antara development build dan production build itu bumi dan langit. Jangan pernah deploy development build ke production!
9. Tips Umum Lainnya
- Jaga Ukuran Komponen Tetap Kecil: Komponen yang terlalu besar dan melakukan terlalu banyak hal cenderung lebih susah dioptimasi dan lebih gampang re-render karena banyak dependensi. Pecah komponen besar jadi komponen-komponen kecil yang lebih spesifik.
- Hindari Inline Function di JSX (Dalam Kasus Tertentu): Bikin fungsi baru di dalam render method (misalnya
onClick={() => doSomething(item.id)}
) itu bikin fungsi baru tiap kali komponen re-render. Kalau fungsi ini dikasih ke komponen anak yang di-memoize, ini bisa micu re-render yang nggak perlu. PakeuseCallback
kalau memang perlu pass fungsi ke komponen anak yang di-memoize, atau definisiin fungsi di luar render method kalau nggak butuh akses scope komponen. Tapi inget,useCallback
juga ada overhead. Jangan terlalu kaku soal ini, profiling lebih penting. - Optimalkan CSS: CSS yang nggak efisien atau terlalu banyak bisa bikin browser lama render elemen. Gunain CSS-in-JS yang efektif atau metodologi CSS yang baik.
- Pake Library yang Performa-Friendly: Beberapa library punya implementasi yang lebih performa dibanding yang lain. Riset sebelum milih library, terutama untuk hal-hal krusial kayak state management atau UI components.
- Testing di Berbagai Perangkat: Performa bisa beda di perangkat yang beda (desktop vs mobile, high-end vs low-end). Selalu uji performa di perangkat target kamu.
- Pantau Terus: Performa aplikasi itu bukan sesuatu yang diurus sekali terus kelar. Fitur baru, library baru, atau perubahan data bisa ngaruh ke performa. Pantau performa aplikasi kamu secara berkala (pake tools kayak Lighthouse, WebPageTest, atau monitoring di production).
Kesimpulan
Bikin aplikasi ReactJS yang ngebut itu butuh perhatian khusus, nggak cuma nulis kode yang jalan aja. Dengan menerapkan tips-tips di atas – mulai dari memoization di level komponen (React.memo
), nilai (useMemo
), dan fungsi (useCallback
), sampe optimasi skala besar kayak lazy loading dan virtualisasi list, ngatur data fetching dan state, sampe optimasi proses build – kamu bisa bikin aplikasi yang jauh lebih responsif dan menyenangkan buat user.
Yang paling penting, jangan langsung optimasi membabi buta. Identifikasi dulu mana bagian yang paling lambat pake profiler dan tools monitoring lainnya. Optimasi di tempat yang tepat bakal ngasih dampak paling besar. Semangat ngoding dan bikin aplikasi React kamu makin ngebut!