<StrictMode> to komponent Reacta, który włącza dodatkowe sprawdzenia dla wszystkiego w swoim środku, tylko w trybie deweloperskim. Renderuje każdy komponent dwa razy, przy montowaniu uruchamia setup każdego efektu, jego funkcję czyszczącą i znowu setup, dwukrotnie uruchamia ref callbacki i ostrzega przed przestarzałymi API. Dlatego useEffect w trybie deweloperskim „uruchamia się dwa razy". W buildzie produkcyjnym nic nie robi.
Włączasz go, owijając aplikację, zwykle w 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>,
);
Podglądy na tej stronie działają jak build produkcyjny, więc StrictMode nie miałby w nich widocznego efektu. Zamiast tego każdy przykład poniżej zawiera taki błąd, dla którego istnieje StrictMode, i pozwala wywołać go ręcznie. Tutaj efekt dodaje nasłuchiwanie kliknięć na document i nigdy go nie usuwa. Kilka razy ukryj i pokaż panel, a potem kliknij stronę.
Każde Show dodaje kolejne nasłuchiwanie, a żadne nie jest usuwane, więc jedno kliknięcie wypisuje log raz na każde zamontowanie. To wyciek, który użytkownik może spowodować, otwierając i zamykając panel. StrictMode pokazałby go już przy pierwszym zamontowaniu: w trybie deweloperskim montuje, odmontowuje i montuje ponownie, więc zobaczyłbyś dwie linie logu na kliknięcie, zanim w ogóle dotkniesz przycisku.
Efekty: setup, cleanup, setup
Przy montowaniu StrictMode uruchamia twój efekt, potem jego funkcję czyszczącą, a potem znowu efekt. Symuluje to, co dzieje się, gdy użytkownik opuszcza ekran i do niego wraca, i sprawdza, czy twoja funkcja czyszcząca cofa to, co zrobił setup. Jeśli tak, drugi setup zostawia wszystko dokładnie tak, jak zrobiłby to jeden, i nie widzisz nic złego. Jeśli nie, błąd pojawia się od razu.
Poprawką dla loggera jest funkcja czyszcząca, która usuwa tę samą funkcję, którą dodała:
Przełączaj, ile chcesz: dopóki logger jest pokazany, każde kliknięcie wypisuje jedną linię. Pod StrictMode w trybie deweloperskim konsola zaczynałaby się od setup, cleanup, setup, a aplikacja nadal zachowywałaby się poprawnie. Ta sekwencja to oznaka zdrowego efektu, a nie problem do wyłączenia.
Częste efekty, które potrzebują funkcji czyszczącej: nasłuchiwanie zdarzeń, setInterval i setTimeout, subskrypcje, połączenia WebSocket albo czatu i żądania, których odpowiedź powinna zostać zignorowana, jeśli komponentu już nie ma. Strona o useEffect pokazuje wzorzec czyszczenia dla każdego z nich.
Renderowanie: wywoływane dwa razy
StrictMode wywołuje też funkcję twojego komponentu dwa razy przy każdym renderowaniu (oraz funkcje, które przekazujesz do useState, useMemo i useReducer, a w klasach constructor, render i shouldComponentUpdate). React zachowuje wynik jednego wywołania, a drugi wyrzuca. Czysty komponent za oba razy zwraca ten sam JSX, więc nic się nie zmienia.
Komponent, który podczas renderowania zmienia coś poza sobą, nie jest czysty, a dwukrotne wywołanie sprawia, że zmiana następuje dwa razy. Ten dodaje wpis "rendered at" do tablicy, którą dostaje jako prop:
Każde ponowne renderowanie dodaje wpis, o który nikt nie prosił. Tutaj zauważasz to dopiero po kliknięciu. Pod StrictMode już pierwsze renderowanie pokazałoby dwa nowe wpisy zamiast jednego. Poprawka to liczenie podczas renderowania bez mutacji: const shown = [...entries, 'extra'].
React 19 dodaje jeden szczegół: podczas podwójnego renderowania useMemo i useCallback ponownie używają wyniku z pierwszego wywołania, zamiast liczyć go dwa razy.
Ref callbacki
Od React 19 StrictMode uruchamia też ref callbacki dwa razy przy montowaniu: podłączenie, czyszczenie, podłączenie. Ref callback, który dodaje nasłuchiwanie albo gdzieś rejestruje węzeł, musi zwracać funkcję czyszczącą, dokładnie jak efekt:
<div
ref={(node) => {
const observer = new ResizeObserver(onResize);
observer.observe(node);
return () => observer.disconnect();
}}
/>
Ostrzeżenia o przestarzałych API
StrictMode ostrzega przed API, które są na wylocie, głównie w komponentach klasowych, takich jak stare metody cyklu życia UNSAFE_componentWillMount, UNSAFE_componentWillReceiveProps i UNSAFE_componentWillUpdate. Niektóre API, przed którymi kiedyś ostrzegał, takie jak string refs i findDOMNode, zostały w React 19 całkowicie usunięte.
Włączanie dla części aplikacji
<StrictMode> to zwykły komponent, więc możesz owinąć nim tylko część drzewa. Pomaga to przy wprowadzaniu go do dużej aplikacji: zacznij od nowych ekranów i rozszerzaj zakres.
function App() {
return (
<>
<Header />
<StrictMode>
<Sidebar />
<Content />
</StrictMode>
<Footer />
</>
);
}
Sidebar i Content (i wszystko, co renderują) dostają sprawdzenia; Header i Footer nie. Nie da się wyłączyć go dla poddrzewa wewnątrz części objętej trybem strict.
Gdzie jest domyślnie włączony:
- Vite: szablon React owija
<App />w<StrictMode>wmain.jsx. - Next.js: App Router włącza go domyślnie; steruje nim
reactStrictModewnext.config.js.
Na produkcji nic nie robi
Build produkcyjny ignoruje <StrictMode>: jedno renderowanie, jedno uruchomienie efektu, żadnych ostrzeżeń. Podwójne wywołania nigdy więc nic nie kosztują twoich użytkowników i nie ma powodu usuwać opakowania przed wdrożeniem.
Jeśli podwójny efekt coś psuje w trybie deweloperskim, na przykład żądanie wysyłane dwa razy albo zdarzenie analityczne zapisywane dwa razy, to jest informacja. Najczęściej poprawką jest funkcja czyszcząca (flaga ignore dla żądania, rozłączenie dla połączenia). Dla czegoś, co naprawdę musi wydarzyć się raz na załadowanie aplikacji, na przykład inicjalizacji SDK, uruchom to poza jakimkolwiek komponentem na poziomie modułu albo zabezpiecz flagą na poziomie modułu.
let didInit = false;
function App() {
useEffect(() => {
if (didInit) return;
didInit = true;
initAnalytics(); // runs once per page load, even in StrictMode
}, []);
}
Unikaj popularnego obejścia z refem, który pomija drugie uruchomienie efektu. Ukrywa ostrzeżenie bez naprawienia brakującej funkcji czyszczącej, a błąd wraca, gdy komponent pierwszy raz naprawdę się odmontuje i zamontuje ponownie, tak jak logger powyżej.
Najczęściej zadawane pytania
Co robi React StrictMode?
Tylko w trybie deweloperskim renderuje każdy komponent w swoim środku dwa razy, przy montowaniu komponentu uruchamia setup każdego efektu, jego funkcję czyszczącą i znowu setup, w ten sam sposób dwukrotnie uruchamia ref callbacki i ostrzega przed przestarzałymi API. Dodatkowe wywołania ujawniają renderowania, które nie są czyste, i efekty bez funkcji czyszczącej.
Dlaczego mój useEffect uruchamia się dwa razy?
Bo komponent jest wewnątrz <StrictMode>, a ty uruchamiasz build deweloperski. React go montuje, symuluje odmontowanie (uruchamia się twoja funkcja czyszcząca) i montuje go ponownie. Jeśli drugi setup powoduje błąd, efektowi brakuje funkcji czyszczącej.
Czy StrictMode wpływa na produkcję?
Nie. Build produkcyjny renderuje raz i uruchamia każdy efekt raz, z <StrictMode> czy bez. Możesz zostawić go w kodzie.
Jak wyłączyć StrictMode?
Usuń opakowanie <StrictMode>, zwykle w main.jsx albo index.js, albo ustaw reactStrictMode: false w next.config.js. Zwykle lepiej naprawić funkcję czyszczącą: podwójne uruchomienie wskazuje na błąd, na który mogą trafić prawdziwi użytkownicy.
Dlaczego console.log wypisuje się dwa razy?
StrictMode w trybie deweloperskim wywołuje funkcję twojego komponentu dwa razy na każde renderowanie. React DevTools może w swoich ustawieniach wyszarzać logi z drugiego wywołania albo je ukrywać.