Domů
» Základní znalosti
»
Jak opravit chybu „Target container is not a DOM element“ v Reactu 18
Jak opravit chybu „Target container is not a DOM element“ v Reactu 18
Nejdůležitější oprava je tato: ujistěte se, že hodnota, kterou předáváte funkci createRoot(), je skutečný DOM element, který již existuje. V Reactu 18 vypadá běžný klientský vstupní bod takto:
import { createRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('root');
if (!container) {
throw new Error('Root element not found');
}
const root = createRoot(container);
root.render(<App />);
Pokud document.getElementById('root') vrátí null, nebo pokud omylem předáte React element, jako je <App />, funkci createRoot(), React nemůže vytvořit kořen a může hlásit chybu „Target container is not a DOM element.“ Dokumentace Reactu k řešení problémů s createRoot definuje tuto chybu přesně v těchto termínech: hodnota předaná funkci createRoot není DOM uzel.
Tato příručka začíná touto vysoce pravděpodobnou příčinou, poté se věnuje problémům s načasováním, chybám při migraci na React 18, serverovému vykreslování, portálům, TypeScriptu a testovacím prostředí, abyste mohli přestat, jakmile narazíte na případ, který odpovídá vaší aplikaci.
Krok 1: Ověřte, co skutečně předáváte funkci createRoot()
Než začnete měnit konfiguraci, zalogujte kontejner:
Pokud konzola vypíše null, React není část, která selhala jako první. Prohlížeč nenašel element s tímto ID v okamžiku, kdy váš kód běžel. Oficiální sekce Reactu pro řešení problémů uvádí neshodu ID a spuštění před existencí DOM uzlu jako běžné důvody.
Pokud konzola vypíše něco jako <div id="root"></div>, pak kontejner existuje a měli byste přejít na níže uvedené kontroly React API, SSR, portálů nebo prostředí.
Platí, když: chyba se objeví okamžitě při spuštění aplikace, zejména v main.jsx, index.jsx nebo index.tsx.
Akce: nehádejte. Zalogujte přesnou hodnotu předanou funkci createRoot(). Pokud je null, opravte důvod, proč vyhledávání v DOM selhalo, než začnete sahat do kódu komponent.
Ilustrace generovaná AI chyby kontejneru v Reactu 18 ve vývojářské konzoli. Nejedná se o snímek obrazovky ze skutečné aplikace nebo React DevTools.
Krok 2: Srovnejte ID v HTML s vyhledáváním v JavaScriptu
Nejjednodušší příčina v reálném světě je neshoda mezi vaším HTML a JavaScriptem.
Vaše HTML může obsahovat:
<div id="app"></div>
zatímco váš vstupní soubor Reactu požaduje:
document.getElementById('root')
Tyto názvy se musí shodovat. Buď změňte markup:
<div id="root"></div>
nebo změňte vyhledávání:
const container = document.getElementById('app');
Aktuální reference createRoot v Reactu používá standardní příklad document.getElementById('root'), ale root není magické povinné ID. Jako kořenový kontejner lze použít jakýkoli skutečný DOM element. Důležitou podmínkou je, že element existuje a že vyhledávání jej vrátí.
Platí, když: nedávno jste změnili HTML šablonu, migrovali z Create React App na Vite nebo jiný bundler, vložili React do existující serverově vykreslené stránky nebo přejmenovali montážní element.
Akce: prohledejte projekt pro id="root" i getElementById('root'). Pokud projekt záměrně používá jiné ID, ujistěte se, že HTML a JavaScript si odpovídají.
Ilustrace generovaná AI montážního elementu s odpovídajícím id="root". Jedná se o konceptuální pohled v editoru kódu, nikoli o snímek obrazovky konkrétní šablony frameworku.
Krok 3: Používejte React 18 root API ve správném pořadí
React 18 zavedl klientské API createRoot. Oficiální průvodce upgradem na React 18 ukazuje migraci ze staršího vzoru ReactDOM.render na:
Překvapivě snadná chyba je prohození rolí DOM kontejneru a React komponenty:
// Špatně
createRoot(<App />);
React to explicitně uvádí jako další běžnou příčinu chyby „Target container is not a DOM element“. Funkce createRoot() přijímá DOM uzel; funkce root.render() přijímá React uzel.
Další chybou při migraci je mentální přenesení signatury z Reactu 17 a pokus předat kontejner funkci root.render():
Reference createRoot v Reactu dokumentuje root.render(reactNode) jako přijímající React uzel, zatímco kontejner patří do createRoot(domNode).
TypeScript: nezaměňujte non-null aserci s opravou za běhu
Průvodce upgradem na React 18 ukazuje createRoot(container!) jako formu pro TypeScript. Vykřičník je aserce v době kompilace: říká TypeScriptu, že věříte, že hodnota není null. Nevytváří chybějící HTML element za běhu.
Bezpečnější vzor při ladění je:
const container = document.getElementById('root');
if (container === null) {
throw new Error('Expected #root to exist');
}
createRoot(container).render(<App />);
To vytvoří užitečnější chybu specifickou pro aplikaci, pokud se HTML a JavaScript rozjedou.
Platí, když: problém se objevil během migrace z Reactu 17 na React 18, po zkopírování vstupního souboru z jiného projektu, nebo pouze v TypeScript sestaveních, kde bylo přidáno ! k umlčení varování kompilátoru.
Akce: ověřte posloupnost volání: vyhledání v DOM → createRoot(container) → root.render(<App />). Při ladění preferujte explicitní kontrolu null před slepým asertováním container!.
Ilustrace generovaná AI defenzivního vzoru pro spuštění Reactu 18. Kód je zobrazen jako konceptuální příklad, nikoli jako zachycený výstup ze skutečného projektu.
Krok 4: Ujistěte se, že váš spouštěcí kód běží až po existenci cílového elementu
ID může být dokonale napsáno a stále vrátit null, pokud váš skript běží dříve, než prohlížeč element zpracoval. Dokumentace Reactu pro řešení problémů specificky varuje, že skript balíčku nemůže vidět DOM uzly, které se objevují později v HTML, pokud dojde k provedení příliš brzy.
To je relevantní hlavně pro vlastní HTML stránky a starší nastavení vložení. Běžné bezpečné rozložení je umístit montážní element před skript:
Pokud kontrolujete vlastní skript, který může běžet před dokončením zpracování, další obrannou možností je počkat na DOMContentLoaded:
function start() {
const container = document.getElementById('root');
if (!container) throw new Error('Root element not found');
createRoot(container).render(<App />);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', start);
} else {
start();
}
Nepřidávejte tento obal automaticky do každého React projektu. Moderní bundlery a frameworky obvykle spravují umístění vstupního skriptu a sémantiku načítání za vás. Pokud standardní aplikace Vite, Next.js, Remix nebo generovaná frameworkem náhle začne hlásit tuto chybu, nejprve hledejte změněnou šablonu, montážní ID, vlastní integraci nebo kód běžící mimo očekávaný klientský vstupní bod prohlížeče.
Platí, když: stejné ID existuje ve finálním HTML, ale vyhledávání je stále null během spouštění, zejména v ručně sestavené HTML stránce, CMS šabloně, vložení widgetu nebo integraci skriptu třetí strany.
Akce: prozkoumejte skutečný zdroj stránky a pořadí provedení. Ujistěte se, že montážní uzel existuje před kódem, který volá createRoot().
Ilustrace generovaná AI ochrany připravenosti DOM pro vlastní bootstrap Reactu. Nejedná se o povinný vzor pro každou aplikaci React 18; použijte ji pouze tehdy, když je načasování spuštění skutečně problém.
Pokud je vaše stránka serverově vykreslována, použijte hydrateRoot místo toho
Existuje důležitá podmínka, kde platný DOM element nestačí k tomu, aby createRoot() bylo správné API. Pokud kontejner již obsahuje HTML vygenerované Reactem na serveru nebo v době sestavení, dokumentace Reactu říká, že místo createRoot() máte použít hydrateRoot().
import { hydrateRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('root');
if (!container) {
throw new Error('Root element not found');
}
hydrateRoot(container, <App />);
Důvod je odlišný od chyby cílového kontejneru. createRoot() spravuje klientsky vykreslený kořen a při prvním vykreslení vymaže existující HTML uvnitř tohoto kořene. hydrateRoot() připojuje React k HTML, které již bylo vyprodukováno Reactem na serveru. Oficiální dokumentace createRoot to explicitně uvádí jako úskalí serverového vykreslování.
Platí, když: máte serverově vykreslené React HTML, statickou generaci, která emituje React markup, nebo framework, který hydratací připojuje React k HTML v prohlížeči.
Akce: neopravujte SSR nahrazením serverového markupu prázdným kontejnerem. Použijte hydratační vstupní bod frameworku nebo React hydrateRoot() podle potřeby.
Pokud je toto cíl pro modální okno nebo tooltip, možná potřebujete createPortal – ne další kořen
Někdy vývojáři vidí chybějící kontejner při pokusu vykreslit modální okno, tooltip, oblast toastu nebo překryv mimo hlavní strom aplikace. Dokumentace Reactu říká, že když chcete, aby se JSX objevil jinde v DOM, použijte createPortal() místo vytváření dalšího kořene jen pro toto podřízené UI.
import { createPortal } from 'react-dom';
function Modal({ children }) {
const modalRoot = document.getElementById('modal-root');
if (!modalRoot) return null;
return createPortal(children, modalRoot);
}
Oficiální dokumentace createPortal říká, že cíl portálu musí již existovat. Portály tedy mohou způsobit související třídu problémů s kontejnerem, pokud chybí modal-root, ale architektonická oprava není nutně „zavolejte znovu createRoot“.
Platí, když: selhávající kontejner není hlavní kořen vaší aplikace, ale cíl překryvu nebo uzel spravovaný mimo normální pozici komponenty v DOM.
Akce: udržujte jeden normální kořen aplikace, pokud opravdu nepotřebujete více nezávislých kořenů. Pro UI ve stylu modálních oken v rámci stejné React aplikace preferujte portál do existujícího DOM uzlu.
Co když k chybě dochází pouze v testech?
Test může selhat ze stejného základního důvodu: očekávaný kontejner nikdy nebyl vložen do testovacího DOM. Pokud váš test ručně volá createRoot(document.getElementById('root')), ujistěte se, že nastavení testu skutečně vytvoří tento uzel před vykreslením.
Mnoho testovacích knihoven pro React však spravuje kontejnery za vás. Pokud již používáte pomocníka render() testovacího frameworku, ruční vytváření React kořene může být zbytečné a může učinit nastavení testu křehčím.
Platí, když: vývoj funguje v prohlížeči, ale Jest, Vitest, JSDOM nebo jiné testovací prostředí vyhazuje chybu kontejneru.
Akce: prozkoumejte nastavení DOM testu, nikoli produkční index.html. Potvrďte, že uzel existuje v prostředí, kde selhávající kód skutečně běží.
Co když není dostupný objekt document?
Pokud kód volající document.getElementById() běží na serveru nebo v jiném prostředí mimo prohlížeč, máte jiný problém s integrací. Klientská API Reactu v react-dom/client jsou určena k vykreslování do DOM uzlů prohlížeče. Serverové vykreslování používá API z react-dom/server a frameworky obvykle oddělují serverové a klientské vstupní body.
Platí, když: chyba se objevuje během serverového vykreslování, kroku sestavení Node nebo kódu sdíleného mezi serverovými a klientskými balíčky.
Akce: přesuňte vytváření kořene pouze pro prohlížeč do klientského vstupního bodu. Pokud používáte framework, řiďte se jeho zdokumentovanou hranicí server/klient místo ručního volání createRoot() ze sdíleného serverového kódu.
Rychlá tabulka diagnostiky
Co vidíte
Pravděpodobná příčina
Nejlepší další kontrola
console.log(container) je null
Neshoda ID nebo element ještě není přítomen
Porovnejte HTML ID a vyhledávání; prozkoumejte načasování skriptu
HTML používá id="app", kód dotazuje root
Neshoda montážního ID
Učiňte oba názvy identickými
createRoot(<App />)
React element předán tam, kde je vyžadován DOM uzel
Předejte DOM uzel funkci createRoot, poté vykreslete <App />
Projekt stále používá ReactDOM.render po upgradu na React 18
Legacy klientské API
Migrujte na createRoot pomocí průvodce upgradem na React 18
Kontejner již obsahuje serverově vykreslené React HTML
Špatná inicializační API klienta
Použijte hydrateRoot
Selhal pouze cíl modálního okna/tooltipu
Chybějící cíl portálu nebo zbytečný další kořen
Použijte createPortal s existujícím DOM uzlem
Selhávají pouze testy
Testovací DOM nikdy nevytvořil cílový element
Vytvořte kontejner v nastavení testu nebo použijte vykreslovač testovací knihovny
Finální ověření: potvrďte opravu místo skrývání chyby
Po provedení změny ověřte cestu spouštění v tomto pořadí:
Otevřete stránku a prozkoumejte konzoli prohlížeče. Chyba cílového kontejneru by měla být pryč.
Spusťte console.log(document.getElementById('root')) a potvrďte, že vypíše skutečný element, nikoli null.
Potvrďte, že importujete createRoot z react-dom/client v klientsky vykreslené aplikaci React 18.
Potvrďte, že DOM element je předán funkci createRoot() a React komponenta je předána funkci root.render().
Pokud byla stránka vykreslena Reactem na serveru, potvrďte, že klient místo toho používá hydrateRoot().
Pokud selhávajícím cílem je modální okno nebo tooltip, potvrďte, že cíl portálu existuje před voláním createPortal().
Nepovažujte aserci non-null v TypeScriptu, volitelné řetězení nebo blok catch za samotnou opravu. Tyto techniky mohou umlčet cestu chyby bez dodání DOM uzlu, který React skutečně potřebuje. Trvalá oprava spočívá v tom, že struktura stránky, inicializační API a načasování provedení budou souhlasit.
Pro normální jednostránkovou aplikaci React 18 je nejkratší správný mentální model: HTML vytvoří kontejner; JavaScript najde tento kontejner; createRoot přijme kontejner; root.render přijme komponentu. Jakmile jsou tyto čtyři části ve správném pořadí, chyba „Target container is not a DOM element“ obvykle zmizí z toho správného důvodu.