Domov
» Základné znalosti
»
Ako opraviť chybu „Target container is not a DOM element“ v React 18
Ako opraviť chybu „Target container is not a DOM element“ v React 18
Najdôležitejšia oprava je nasledovná: uistite sa, že hodnota, ktorú odovzdávate do funkcie createRoot(), je skutočný DOM element, ktorý už existuje. V React 18 vyzerá bežný klientsky 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 />);
Ak document.getElementById('root') vráti null, alebo ak omylom odovzdáte React element, ako je <App />, do funkcie createRoot(), React nedokáže vytvoriť koreň a môže nahlásiť chybu „Target container is not a DOM element“. Dokumentácia Reactu k riešeniu problémov s funkciou createRoot definuje túto chybu presne týmito slovami: hodnota odovzdaná do funkcie createRoot nie je DOM uzol.
Táto príručka začína touto vysoko pravdepodobnou príčinou, potom pokrýva problémy s načasovaním, chyby pri migrácii na React 18, serverové vykresľovanie, portály, TypeScript a testovacie prostredia, aby ste mohli prestať, keď narazíte na prípad, ktorý zodpovedá vašej aplikácii.
Krok 1: Dokážte, čo skutočne odovzdávate do funkcie createRoot()
Pred zmenou konfigurácie záznamujte (logujte) kontajner:
Ak konzola vypíše null, React nie je časťou, ktorá zlyhala ako prvá. Prehliadač nenašiel element s týmto ID v momente, keď sa váš kód spustil. Oficiálna sekcia riešenia problémov Reactu uvádza nesúlad ID a vykonanie pred existenciou DOM uzla ako bežné dôvody.
Ak konzola vypíše niečo ako <div id="root"></div>, potom kontajner existuje a mali by ste preskočiť na nižšie uvedené kontroly React API, SSR, portálov alebo prostredia.
Platí, keď: chyba sa objaví okamžite počas spúšťania aplikácie, najmä v súboroch main.jsx, index.jsx alebo index.tsx.
Akcia: nehádajte. Záznamujte presnú hodnotu odovzdanú do funkcie createRoot(). Ak je null, opravte dôvod, prečo vyhľadávanie v DOM zlyhalo, skôr než sa dotknete kódu komponentov.
Ilustrácia generovaná AI chyby kontajnera v React 18 v konzole vývojára. Nie je to snímka obrazovky zo skutočnej aplikácie ani z React DevTools.
Krok 2: Zosúladte ID v HTML s vyhľadávaním v JavaScripte
Najjednoduchšou príčinou v reálnom svete je nesúlad medzi vaším HTML a JavaScriptom.
Vaše HTML môže obsahovať:
<div id="app"></div>
zatiaľ čo váš vstupný súbor Reactu požaduje:
document.getElementById('root')
Tieto názvy sa musia zhodovať. Buď zmeňte markup:
<div id="root"></div>
alebo zmeňte vyhľadávanie:
const container = document.getElementById('app');
Aktuálna referenčná dokumentácia Reactu pre createRoot používa štandardný príklad document.getElementById('root'), ale root nie je magická povinná ID. Ako koreňový kontajner môže byť použitý akýkoľvek skutočný DOM element. Dôležitou podmienkou je, že element existuje a že vyhľadávanie ho vráti.
Platí, keď: ste nedávno zmenili HTML šablónu, migrovali z Create React App na Vite alebo iný bundler, vložili React do existujúcej stránky vykreslenej na serveri alebo ste premenovali element na pripojenie (mount).
Akcia: vyhľadajte v projekte výrazy id="root" aj getElementById('root'). Ak projekt zámerne používa iné ID, uistite sa, že HTML a JavaScript sú v súlade.
Ilustrácia generovaná AI zodpovedajúceho elementu na pripojenie id="root". Ide o konceptuálny pohľad v editore kódu, nie o snímku obrazovky konkrétnej šablóny frameworku.
Krok 3: Používajte root API Reactu 18 v správnom poradí
React 18 zaviedol klientske API createRoot. Oficiálna príručka na upgrade na React 18 ukazuje migráciu zo staršieho vzoru ReactDOM.render na:
Prekvapivo ľahká chyba je zameniť úlohy DOM kontajnera a React komponentu:
// Nesprávne
createRoot(<App />);
React explicitne uvádza toto ako ďalšiu bežnú príčinu chyby „Target container is not a DOM element“. Funkcia createRoot() prijíma DOM uzol; funkcia root.render() prijíma React uzol.
Dalšou chybou pri migrácii je mentálne prenesenie signatúry z Reactu 17 a pokus odovzdať kontajner do funkcie root.render():
// Nesprávny mentálny model
root.render(<App />, container);
// Správne
const root = createRoot(container);
root.render(<App />);
Referenčná dokumentácia Reactu pre createRoot dokumentuje root.render(reactNode) ako prijímajúcu React uzol, zatiaľ čo kontajner patrí do createRoot(domNode).
TypeScript: nezamieňajte ne-nulový asert s opravou za behu
Príručka na upgrade na React 18 ukazuje createRoot(container!) ako formu pre TypeScript. Výkričník je asercia v čase kompilácie: hovorí TypeScriptu, že veríte, že hodnota nie je null. Nevytvára chýbajúci HTML element za behu.
Bezpečnejší vzor pri ladení je:
const container = document.getElementById('root');
if (container === null) {
throw new Error('Expected #root to exist');
}
createRoot(container).render(<App />);
Toto vyprodukuje užitočnejšiu chybu špecifickú pre aplikáciu, ak sa HTML a JavaScript rozídu.
Platí, keď: problém sa objavil počas migrácie z React 17 na React 18, po skopírovaní vstupného súboru z iného projektu, alebo iba v zostaveniach TypeScriptu, kde bolo pridané ! na umlčanie varovania kompilátora.
Akcia: overte poradie volaní: DOM lookup → createRoot(container) → root.render(<App />). Počas ladenia uprednostnite explicitnú kontrolu null pred slepým asertom container!.
Ilustrácia generovaná AI defenzívneho vzoru spúšťania React 18. Kód je zobrazený ako konceptuálny príklad, nie ako zachytený výstup zo skutočného projektu.
Krok 4: Uistite sa, že váš spúšťací kód beží až po existencii cieľového elementu
ID môže byť dokonale napísané a stále vráti null, ak váš skript beží skôr, než prehliadač parsoval element. Dokumentácia Reactu k riešeniu problémov konkrétne varuje, že skript balíka nemôže vidieť DOM uzly, ktoré sa objavia neskôr v HTML, ak sa vykonanie uskutoční príliš skoro.
Toto je hlavne relevantné pre vlastné HTML stránky a staršie nastavenia vkladania. Bežný bezpečný rozloženie je umiestniť element na pripojenie pred skript:
Ak ovládate vlastný skript, ktorý môže bežať pred dokončením parsovania, ďalšou defenzívnou možnosťou je počkať 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();
}
Nepridávajte tento obal automaticky do každého React projektu. Moderné bundlery a frameworky zvyčajne spravujú umiestnenie vstupného skriptu a sémantiku načítania za vás. Ak stock aplikácia Vite, Next.js, Remix alebo aplikácia generovaná frameworkom náhle vyvinie túto chybu, najprv hľadajte zmenenú šablónu, ID na pripojenie, vlastnú integráciu alebo kód bežiaci mimo očakávaného vstupného bodu prehliadača.
Platí, keď: rovnaké ID existuje v konečnom HTML, ale vyhľadávanie je stále null počas spúšťania, najmä v ručne zostavenej HTML stránke, šablóne CMS, widget embede alebo integrácii skriptu tretej strany.
Akcia: preskúmajte skutočný zdroj stránky a poradie vykonávania. Uistite sa, že uzol na pripojenie existuje pred kódom, ktorý volá createRoot().
Ilustrácia generovaná AI stráže pripravenosti DOM pre vlastný React bootstrap. Nie je to povinný vzor pre každú React 18 aplikáciu; použite ju iba vtedy, ak je načasovanie spustenia skutočne problémom.
Ak je vaša stránka vykreslená na serveri, použite hydrateRoot namiesto toho
Existuje dôležitá podmienka, kde platný DOM element nestačí na to, aby bol createRoot() správne API. Ak kontajner už obsahuje HTML generované Reactom na serveri alebo v čase zostavenia, dokumentácia Reactu hovorí, že treba použiť hydrateRoot() namiesto createRoot().
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 cieľového kontajnera. createRoot() spravuje klientsky vykreslený koreň a pri prvom vykreslení vymaže existujúce HTML vnútri tohto koreňa. hydrateRoot() pripája React k HTML, ktoré už bolo vytvorené Reactom na serveri. Oficiálna dokumentácia createRoot to explicitne uvádza ako úskalie serverového vykresľovania.
Platí, keď: máte React HTML vykreslené na serveri, statickú generáciu, ktorá emituje React markup, alebo framework, ktorý hydratuje HTML v prehliadači.
Akcia: neopravujte SSR nahradením serverového markupu prázdym kontajnerom. Použite hydratačný vstupný bod frameworku alebo React hydrateRoot() podľa potreby.
Ak je toto cieľ pre modal alebo tooltip, možno potrebujete createPortal – nie ďalší root
Niekedy vývojári vidia chýbajúci kontajner pri pokuse vykresliť modal, tooltip, oblasť toastov alebo overlay mimo hlavnej stromovej štruktúry aplikácie. Dokumentácia Reactu hovorí, že keď chcete, aby sa JSX objavil inde v DOM, použite createPortal() namiesto vytvárania ďalšieho koreňa len pre toto detské UI.
import { createPortal } from 'react-dom';
function Modal({ children }) {
const modalRoot = document.getElementById('modal-root');
if (!modalRoot) return null;
return createPortal(children, modalRoot);
}
Oficiálna dokumentácia createPortal hovorí, že cieľ portálu musí už existovať. Portály teda môžu spôsobiť súvisiacu triedu problémov s kontajnerom, ak modal-root chýba, ale architektonická oprava nie je nutne „zavolať createRoot znova“.
Platí, keď: zlyhávajúci kontajner nie je hlavný koreň vašej aplikácie, ale cieľ overlayu alebo uzol spravovaný mimo normálnej DOM pozície komponentu.
Akcia: udržujte jeden normálny koreň aplikácie, pokiaľ skutočne nepotrebujete viacero nezávislých koreňov. Pre UI štýlu modal v rámci tej istej React aplikácie uprednostnite portál do existujúceho DOM uzla.
Čo ak sa chyba vyskytuje iba v testoch?
Test môže zlyhať z rovnakého fundamentálneho dôvodu: očakávaný kontajner nikdy nebol vložený do testovacieho DOM. Ak váš test manuálne volá createRoot(document.getElementById('root')), uistite sa, že nastavenie testu skutočne vytvára tento uzol pred vykreslením.
Avšak, mnoho testovacích knižníc Reactu spravuje kontajnery za vás. Ak už používate pomocníka render() testovacieho frameworku, manuálne vytváranie React koreňa môže byť zbytočné a môže spraviť nastavenie testu krehkejším.
Platí, keď: vývoj funguje v prehliadači, ale Jest, Vitest, JSDOM alebo iné testovacie prostredie vyhodí chybu kontajnera.
Akcia: preskúmajte DOM nastavenie testu, nie produkčný index.html. Potvrďte, že uzol existuje v prostredí, kde sa zlyhávajúci kód skutočne vykonáva.
Čo ak je dokument nedostupný?
Ak kód, ktorý volá document.getElementById(), sa vykonáva na serveri alebo v inom neprehliadačovom prostredí, máte iný problém s integráciou. Klientske API Reactu v react-dom/client sú navrhnuté na vykresľovanie do DOM uzlov prehliadača. Serverové vykresľovanie používa API z react-dom/server a frameworky normálne oddeľujú serverové a klientske vstupné body.
Platí, keď: chyba sa objaví počas server-side renderingu, kroku zostavenia Node alebo kódu zdieľaného medzi serverovými a prehliadačovými bundle.
Akcia: presuňte vytváranie koreňa určené iba pre prehliadač do klientskeho vstupného bodu. Ak používate framework, dodržiavajte jeho dokumentovanú hranicu server/client namiesto manuálneho volania createRoot() zo zdieľaného serverového kódu.
Rýchla diagnostická tabuľka
Čo vidíte
Pravdepodobná príčina
Najlepšia ďalšia kontrola
console.log(container) je null
Nesúlad ID alebo element ešte nie je prítomný
Porovnajte HTML ID a vyhľadávanie; preskúmajte načasovanie skriptu
HTML používa id="app", kód dopytuje root
Nesúlad ID na pripojenie
Urobte obe mená identickými
createRoot(<App />)
React element odovzdaný tam, kde je vyžadovaný DOM uzol
Odovzdajte DOM uzol do createRoot, potom vykreslite <App />
Projekt stále používa ReactDOM.render po upgrade na React 18
Legacy klientske API
Migrujte na createRoot pomocou príručky na upgrade na React 18
Kontajner už obsahuje React HTML vykreslené na serveri
Nesprávne klientske inicializačné API
Použite hydrateRoot
Zlyháva iba cieľ modal/tooltip
Chýbajúci cieľ portálu alebo zbytočný ďalší root
Použite createPortal s existujúcim DOM uzlom
Zlyhávajú iba testy
Testovací DOM nikdy nevytvoril cieľový element
Vytvorte kontajner v nastavení testu alebo použite renderer testovacej knižnice
Finálna verifikácia: potvrďte opravu namiesto skrývania chyby
Po vykonaní zmeny overte cestu spustenia v tomto poradí:
Otvorte stránku a preskúmajte konzolu prehliadača. Chyba cieľového kontajnera by mala byť preč.
Spustite console.log(document.getElementById('root')) a potvrďte, že vypíše skutočný element, nie null.
Potvrďte, že importujete createRoot z react-dom/client v klientsky vykreslenej aplikácii React 18.
Potvrďte, že DOM element je odovzdaný do createRoot() a React komponent je odovzdaný do root.render().
Ak bola stránka vykreslená Reactom na serveri, potvrďte, že klient používa namiesto toho hydrateRoot().
Ak zlyhávajúcim cieľom je modal alebo tooltip, potvrďte, že cieľ portálu existuje pred volaním createPortal().
Nepovažujte ne-nulový asert TypeScriptu, voliteľné reťazenie alebo catch blok za samotnú opravu. Tieto techniky môžu umlčať cestu chyby bez dodania DOM uzla, ktorý React skutočne potrebuje. Trvalá oprava je dosiahnuť súlad štruktúry stránky, inicializačného API a načasovania vykonávania.
Pre normálnu jednostránkovú aplikáciu React 18 je najkratší správny mentálny model: HTML vytvára kontajner; JavaScript nájde tento kontajner; createRoot prijíma kontajner; root.render prijíma komponent. Keď sú tieto štyri časti v správnom poradí, chyba „Target container is not a DOM element“ zvyčajne zmizne z správneho dôvodu.