<StrictMode> adalah komponen React yang menyalakan pemeriksaan tambahan untuk semua yang ada di dalamnya, hanya di development. Komponen ini merender setiap komponen dua kali, menjalankan setup, cleanup, lalu setup lagi untuk setiap effect saat mount, menjalankan ref callback dua kali, dan memperingatkan API usang. Inilah sebabnya useEffect "berjalan dua kali" di development. Di build production, komponen ini tidak melakukan apa pun.
Kamu mengaktifkannya dengan membungkus aplikasimu, biasanya di main.jsx:
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.jsx';
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
);
Pratinjau di halaman ini berjalan seperti build production, jadi StrictMode tidak akan memberi efek yang terlihat di sana. Sebagai gantinya, setiap contoh di bawah berisi jenis bug yang memang ingin ditangkap StrictMode, dan membiarkanmu memicunya secara manual. Di sini sebuah effect menambahkan listener klik ke document dan tidak pernah menghapusnya. Sembunyikan dan tampilkan panelnya beberapa kali, lalu klik halaman.
Setiap Show menambah satu listener lagi, dan tidak ada yang dihapus, jadi satu klik mencatat log sekali untuk setiap mount. Itu kebocoran yang bisa ditimbulkan pengguna hanya dengan membuka dan menutup panel. StrictMode akan memperlihatkannya sejak mount pertama: di development, StrictMode me-mount, unmount, lalu me-mount lagi, jadi kamu akan melihat dua baris log per klik bahkan sebelum menyentuh tombol.
Effect: setup, cleanup, setup
Saat mount, StrictMode menjalankan effect-mu, lalu cleanup-nya, lalu effect itu lagi. StrictMode sedang menyimulasikan apa yang terjadi saat pengguna meninggalkan sebuah layar lalu kembali, dan memeriksa bahwa cleanup-mu membatalkan setup-mu. Kalau begitu, setup kedua akan meninggalkan keadaan persis seperti satu kali setup, dan kamu tidak melihat ada yang salah. Kalau tidak, bug-nya langsung muncul.
Perbaikan untuk logger itu adalah cleanup yang menghapus fungsi yang sama dengan yang ditambahkan:
Toggle sesering yang kamu mau: setiap klik mencatat satu baris selama logger ditampilkan. Di bawah StrictMode dalam development, console akan diawali dengan setup, cleanup, setup, dan aplikasinya tetap berperilaku benar. Urutan itu adalah tanda effect yang sehat, bukan masalah yang perlu dimatikan.
Effect yang umum dan butuh cleanup: event listener, setInterval dan setTimeout, subscription, koneksi WebSocket atau chat, dan request yang respons-nya harus diabaikan kalau komponennya sudah hilang. Halaman useEffect menunjukkan pola cleanup untuk masing-masing.
Render: dipanggil dua kali
StrictMode juga memanggil fungsi komponenmu dua kali untuk setiap render (begitu juga fungsi yang kamu berikan ke useState, useMemo, dan useReducer, serta constructor, render, dan shouldComponentUpdate pada class). React menyimpan hasil dari satu pemanggilan dan membuang yang lain. Komponen yang murni mengembalikan JSX yang sama di kedua pemanggilan, jadi tidak ada yang berubah.
Komponen yang mengubah sesuatu di luar dirinya saat render tidaklah murni, dan memanggilnya dua kali membuat perubahan itu terjadi dua kali. Komponen ini menambahkan entri "rendered at" ke array yang diterimanya sebagai prop:
Setiap render ulang menambahkan entri yang tidak diminta siapa pun. Di sini kamu baru menyadarinya setelah mengklik. Di bawah StrictMode, render pertama saja sudah akan menampilkan dua entri baru, bukan satu. Perbaikannya adalah menghitung saat render tanpa melakukan mutasi: const shown = [...entries, 'extra'].
React 19 menambahkan satu detail: selama render ganda, useMemo dan useCallback memakai ulang hasil dari pemanggilan pertama alih-alih menghitungnya dua kali.
Ref callback
Sejak React 19, StrictMode juga menjalankan ref callback dua kali saat mount: pasang, cleanup, pasang. Ref callback yang menambahkan listener atau mendaftarkan node ke suatu tempat perlu mengembalikan cleanup, persis seperti effect:
<div
ref={(node) => {
const observer = new ResizeObserver(onResize);
observer.observe(node);
return () => observer.disconnect();
}}
/>
Peringatan API usang
StrictMode memperingatkan API yang akan dihapus, sebagian besar di class component, seperti lifecycle lama UNSAFE_componentWillMount, UNSAFE_componentWillReceiveProps, dan UNSAFE_componentWillUpdate. Beberapa API yang dulu diperingatkannya, seperti string ref dan findDOMNode, sudah dihapus sepenuhnya dari React 19.
Mengaktifkannya untuk sebagian aplikasi
<StrictMode> adalah komponen biasa, jadi kamu bisa membungkus sebagian pohon saja. Ini membantu saat mengadopsinya di aplikasi besar: mulai dari layar-layar baru lalu perluas.
function App() {
return (
<>
<Header />
<StrictMode>
<Sidebar />
<Content />
</StrictMode>
<Footer />
</>
);
}
Sidebar dan Content (beserta semua yang dirender keduanya) mendapat pemeriksaan; Header dan Footer tidak. Tidak ada cara untuk mematikannya bagi sebuah subtree di dalam bagian yang strict.
Di mana StrictMode aktif secara default:
- Vite: template React membungkus
<App />dengan<StrictMode>dimain.jsx. - Next.js: App Router mengaktifkannya secara default;
reactStrictModedinext.config.jsmengaturnya.
Di production, StrictMode tidak melakukan apa pun
Build production mengabaikan <StrictMode>: satu render, satu kali effect berjalan, tanpa peringatan. Jadi pemanggilan ganda itu tidak pernah merugikan penggunamu, dan tidak ada alasan untuk menghapus pembungkusnya sebelum deploy.
Kalau effect ganda merusak sesuatu di development, misalnya request terkirim dua kali atau event analytics tercatat dua kali, itu adalah informasi. Sebagian besar waktu, perbaikannya adalah cleanup (flag ignore untuk request, disconnect untuk koneksi). Untuk sesuatu yang benar-benar harus terjadi sekali per pemuatan aplikasi, seperti inisialisasi SDK, jalankan di luar komponen mana pun di tingkat module, atau lindungi dengan flag di tingkat module.
let didInit = false;
function App() {
useEffect(() => {
if (didInit) return;
didInit = true;
initAnalytics(); // runs once per page load, even in StrictMode
}, []);
}
Hindari trik umum berupa ref yang melewatkan run effect kedua. Trik itu menyembunyikan peringatan tanpa memperbaiki cleanup yang hilang, dan bug-nya kembali saat komponen benar-benar unmount lalu di-mount lagi untuk pertama kalinya, seperti yang dilakukan logger di atas.
Pertanyaan yang sering diajukan
Apa fungsi React StrictMode?
Hanya di development, StrictMode merender setiap komponen di dalamnya dua kali, menjalankan setup, cleanup, lalu setup lagi untuk setiap effect saat komponen di-mount, menjalankan ref callback dua kali dengan cara yang sama, dan memperingatkan API usang. Pemanggilan tambahan itu membongkar render yang tidak murni dan effect yang tidak punya cleanup.
Mengapa useEffect saya berjalan dua kali?
Karena komponennya ada di dalam <StrictMode> dan kamu sedang menjalankan build development. React me-mount komponen, menyimulasikan unmount (cleanup-mu berjalan), lalu me-mount lagi. Kalau setup kedua menimbulkan bug, berarti effect itu tidak punya cleanup.
Apakah StrictMode memengaruhi production?
Tidak. Build production merender sekali dan menjalankan setiap effect sekali, dengan atau tanpa <StrictMode>. Kamu boleh membiarkannya di kodemu.
Bagaimana cara menonaktifkan StrictMode?
Hapus pembungkus <StrictMode>, biasanya di main.jsx atau index.js, atau atur reactStrictMode: false di next.config.js. Memperbaiki cleanup biasanya lebih baik: pemanggilan ganda itu sedang menunjuk ke bug yang bisa dialami pengguna sungguhan.
Mengapa console.log tercetak dua kali?
StrictMode memanggil fungsi komponenmu dua kali per render di development. React DevTools bisa membuat log dari pemanggilan kedua tampil abu-abu, atau menyembunyikannya, lewat pengaturannya.