Hjem
» Basis viden
»
Sådan løser du fejlen 'Target container is not a DOM element' i React 18
Sådan løser du fejlen 'Target container is not a DOM element' i React 18
Den vigtigste løsning er denne: Sørg for, at den værdi, du sender til createRoot(), er et faktisk DOM-element, der allerede eksisterer. I React 18 ser det normale klient-startpunkt sådan ud:
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 />);
Hvis document.getElementById('root') returnerer null, eller hvis du ved en fejl sender et React-element som <App /> til createRoot(), kan React ikke oprette en rod og rapportere fejlen “Target container is not a DOM element.” Reacts egen fejlfinding-dokumentation for createRoot definerer fejlen præcis på denne måde: Værdien, der sendes til createRoot, er ikke et DOM-node.
Denne guide starter med den mest sandsynlige årsag og dækker derefter timing-problemer, migreringsfejl fra React 18, server-rendering, portals, TypeScript og testmiljøer, så du kan stoppe, når du finder den sag, der matcher din app.
Trin 1: Bevis hvad du faktisk sender til createRoot()
Før du ændrer konfigurationen, skal du logge containeren:
Hvis konsollen udskriver null, er det ikke React, der fejlede først. Browseren fandt ikke et element med det ID på det tidspunkt, din kode kørte. Reacts officielle fejlfindingsafsnit nævner et ID-mismatch og eksekvering før DOM-noden eksisterer som almindelige årsager.
Hvis konsollen udskriver noget i stil med <div id="root"></div>, så eksisterer containeren, og du skal springe videre til React API-, SSR-, portal- eller miljøkontrollerne nedenfor.
Gælder når: Fejlen opstår øjeblikkeligt under opstart af applikationen, især i main.jsx, index.jsx eller index.tsx.
Handling: Gæt ikke. Log den præcise værdi, der sendes til createRoot(). Hvis den er null, skal du løse årsagen til, at DOM-opslaget fejlede, før du rører komponentkoden.
AI-genereret illustration af React 18-containerfejlen i en udviklerkonsol. Det er ikke et skærmbillede fra en rigtig applikation eller React DevTools.
Trin 2: Få HTML-ID'et til at matche JavaScript-opslaget
Den simpleste årsag i den virkelige verden er et mismatch mellem din HTML og din JavaScript.
Din HTML kan indeholde:
<div id="app"></div>
Mens din React-entry-fil spørger efter:
document.getElementById('root')
Disse navne skal matche. Enten ændrer du markuppen:
<div id="root"></div>
Eller ændrer du opslaget:
const container = document.getElementById('app');
Reacts nuværende createRoot-reference bruger standardeksemplet document.getElementById('root'), men root er ikke et magisk påkrævet ID. Ethvert rigtigt DOM-element kan bruges som rod-container. Den vigtige betingelse er, at elementet eksisterer, og at opslaget returnerer det.
Gælder når: Du har for nylig ændret en HTML-skabelon, migreret fra Create React App til Vite eller en anden bundler, indlejret React i en eksisterende server-renderet side, eller omdøbt mount-elementet.
Handling: Søg i projektet efter både id="root" og getElementById('root'). Hvis projektet bevidst bruger et andet ID, skal du få HTML og JavaScript til at være enige.
AI-genereret illustration af et matchende id="root" mount-element. Det er en konceptuel kodeeditor-visning, ikke et skærmbillede af en bestemt frameworks-skabelon.
Trin 3: Brug React 18 rod-API'en i den korrekte rækkefølge
React 18 introducerede klient-API'en createRoot. Den officielle React 18 opgraderingsguide viser migreringen fra det ældre ReactDOM.render-mønster til:
En overraskende let fejl er at bytte om på DOM-containeren og React-komponenten:
// Forkert
createRoot(<App />);
React nævner eksplicit dette som en anden almindelig årsag til fejlen “Target container is not a DOM element”. createRoot() modtager DOM-noden; root.render() modtager React-noden.
En anden migreringsfejl er at tage React 17-signaturen med mentalt og forsøge at sende containeren til root.render():
Reacts createRoot-reference dokumenterer root.render(reactNode) som tagende React-noden, mens containeren hører til createRoot(domNode).
TypeScript: Forveksl ikke non-null assertion med en runtime-løsning
React 18 opgraderingsguiden viser createRoot(container!) som en TypeScript-form. Udråbstegnet er en compile-time assertion: Det fortæller TypeScript, at du tror, værdien ikke er null. Det opretter ikke et manglende HTML-element ved runtime.
Et sikrere mønster, når du debugger, er:
const container = document.getElementById('root');
if (container === null) {
throw new Error('Expected #root to exist');
}
createRoot(container).render(<App />);
Dette producerer en mere nyttig applikationsspecifik fejl, hvis HTML og JavaScript driver fra hinanden.
Gælder når: Problemet opstod under en migrering fra React 17 → React 18, efter at have kopieret en entry-fil fra et andet projekt, eller kun i TypeScript-builds, hvor ! blev tilføjet for at dæmpe en compiler-advarsel.
Handling: Verificer kaldsekvensen: DOM lookup → createRoot(container) → root.render(<App />). Foretræk en eksplicit null-check frem for blindt at assertere container! under debugging.
AI-genereret illustration af et defensivt React 18 opstartsmønster. Koden vises som et konceptuelt eksempel, ikke som fanget output fra et faktisk projekt.
Trin 4: Sørg for, at din opstartskode kører, efter at målelementet eksisterer
Et ID kan være perfekt stavet og stadig returnere null, hvis dit script kører, før browseren har parset elementet. Reacts fejlfindingsdokumentation advarer specifikt om, at et bundle-script ikke kan se DOM-noder, der dukker op senere i HTML'en, hvis eksekveringen sker for tidligt.
Dette er primært relevant for brugerdefinerede HTML-sider og ældre indlejringssætups. Et almindeligt sikkert layout er at placere mount-elementet før scriptet:
Hvis du styrer et brugerdefineret script, der kan køre, før parsing er færdig, er en anden defensiv mulighed at vente på 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();
}
Tilføj ikke denne wrapper automatisk til alle React-projekter. Moderne bundlers og frameworks håndterer typisk placering og indlæsningssemantik for entry-scripts for dig. Hvis en standard Vite, Next.js, Remix eller framework-genereret app pludselig udvikler denne fejl, skal du først kigge efter en ændret skabelon, mount-ID, brugerdefineret integration eller kode, der kører uden for det forventede browser-startpunkt.
Gælder når: Det samme ID eksisterer i den endelige HTML, men opslaget er stadig null under opstart, især i en manuelt samlet HTML-side, CMS-skabelon, widget-indlejring eller tredjeparts-script-integration.
Handling: Inspectér den faktiske sidekilde og eksekveringsrækkefølgen. Sørg for, at mount-noden eksisterer, før koden, der kalder createRoot().
AI-genereret illustration af en DOM-readiness-guard for en brugerdefineret React bootstrap. Det er ikke et påkrævet mønster for alle React 18 apps; brug det kun, når opstartstiming faktisk er problemet.
Hvis din side er server-renderet, skal du bruge hydrateRoot i stedet
Der er en vigtig betingelse, hvor et gyldigt DOM-element ikke er nok til at gøre createRoot() til den korrekte API. Hvis containeren allerede indeholder HTML genereret af React på serveren eller ved build-tid, siger Reacts dokumentation, at du skal bruge hydrateRoot() i stedet for 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 />);
Årsagen er forskellig fra target-container-fejlen. createRoot() administrerer en klient-renderet rod og rydder eksisterende HTML inde i den rod ved den første render. hydrateRoot() tilknytter React til HTML, der allerede er produceret af React på serveren. Den officielle createRoot-dokumentation fremhæver dette eksplicit som en server-rendering faldgrube.
Gælder når: Du har server-renderet React HTML, statisk generering, der udsender React markup, eller et framework, der hydrerer HTML i browseren.
Handling: “Fix” ikke SSR ved at erstatte server markup med en tom container. Brug frameworkets hydrerings-entry-punkt eller Reacts hydrateRoot() som passende.
Hvis dette er en modal eller tooltip-mål, har du måske brug for createPortal – ikke en anden rod
Nogle gange ser udviklere en manglende container, mens de forsøger at render en modal, tooltip, toast-region eller overlay uden for det primære app-træ. Reacts docs siger, at når du vil have JSX til at dukke op et andet sted i DOM'en, skal du bruge createPortal() frem for at oprette en anden rod kun for den børne-UI.
import { createPortal } from 'react-dom';
function Modal({ children }) {
const modalRoot = document.getElementById('modal-root');
if (!modalRoot) return null;
return createPortal(children, modalRoot);
}
Den officielle createPortal-dokumentation siger, at portal-målet allerede skal eksistere. Så portals kan producere en relateret klasse af container-problemer, hvis modal-root mangler, men den arkitektoniske løsning er ikke nødvendigvis “kald createRoot igen”.
Gælder når: Den fejlede container er ikke din applikations primære rod, men en overlay-destination eller en node administreret uden for komponentens normale DOM-position.
Handling: Behold én normal applikationsrod, medmindre du virkelig har brug for flere uafhængige rødder. For modal-stil UI inden for den samme React-applikation, foretræk en portal til et eksisterende DOM-node.
Hvad nu, hvis fejlen kun sker i tests?
En test kan fejle af samme fundamentale årsag: Den forventede container blev aldrig indsat i test-DOM'en. Hvis din test manuelt kalder createRoot(document.getElementById('root')), skal du sikre dig, at testopsætningen faktisk opretter den node før rendering.
Men mange React-testbiblioteker administrerer containere for dig. Hvis du allerede bruger et testframeworks render()-helper, kan manuel oprettelse af en React rod være unødvendig og gøre testopsætningen mere skrøbelig.
Gælder når: Udvikling virker i browseren, men Jest, Vitest, JSDOM eller et andet testmiljø kaster container-fejlen.
Handling: Inspectér testens DOM-opsætning, ikke den produktions index.html. Bekræft, at noden eksisterer inde i det miljø, hvor den fejlede kode faktisk kører.
Hvad nu, hvis document ikke er tilgængeligt?
Hvis kode, der kalder document.getElementById(), eksekverer i en server eller andet ikke-browser miljø, har du et andet integrationsproblem. Reacts klient-API'er i react-dom/client er designet til at render ind i browser DOM-noder. Server-rendering bruger API'er fra react-dom/server, og frameworks adskiller normalt server- og klient-entry-points.
Gælder når: Fejlen opstår under server-side rendering, et Node build-trin eller kode delt mellem server- og browser-bundles.
Handling: Flyt browser-kun rod-oprettelse ind i klient-entry-pointet. Hvis du bruger et framework, skal du følge dets dokumenterede klient/server-grænse frem for manuelt at kalde createRoot() fra delt serverkode.
Hurtig diagnose-tabel
Hvad du ser
Sandsynlig årsag
Bedste næste kontrol
console.log(container) er null
ID-mismatch eller element ikke til stede endnu
Sammenlign HTML-ID og opslag; inspectér script-timing
HTML bruger id="app", kode spørger efter root
Mount ID-mismatch
Gør begge navne identiske
createRoot(<App />)
React-element sendt hvor DOM-node kræves
Send DOM-noden til createRoot, render derefter <App />
Projektet bruger stadig ReactDOM.render efter en React 18 opgradering
Legacy klient-API
Migrér til createRoot ved hjælp af React 18 opgraderingsguiden
Containeren indeholder allerede server-renderet React HTML
Forkert klient-initialiserings-API
Brug hydrateRoot
Kun en modal/tooltip-mål fejler
Manglende portal-mål eller unødvendig ekstra rod
Brug createPortal med et eksisterende DOM-node
Kun tests fejler
Test-DOM oprettede aldrig målelementet
Opret containeren i testopsætningen eller brug testbibliotekets renderer
Endelig verifikation: Bekræft løsningen i stedet for at skjule fejlen
Efter at have foretaget en ændring, skal du verificere opstartsstien i denne rækkefølge:
Åbn siden og inspectér browserkonsollen. Target-container-fejlen skal være væk.
Kør console.log(document.getElementById('root')) og bekræft, at den udskriver et rigtigt element, ikke null.
Bekræft, at du importerer createRoot fra react-dom/client i en React 18 klient-renderet app.
Bekræft, at DOM-elementet sendes til createRoot() og React-komponenten sendes til root.render().
Hvis siden blev renderet af React på serveren, skal du bekræfte, at klienten bruger hydrateRoot() i stedet.
Hvis den fejlede destination er en modal eller tooltip, skal du bekræfte, at portal-målet eksisterer, før du kalder createPortal().
Overvej ikke en TypeScript non-null assertion, optional chaining eller en catch-blok som løsningen i sig selv. Disse teknikker kan dæmpe en fejlvej uden at levere det DOM-node, React faktisk har brug for. Den holdbare løsning er at få sidestrukturen, initialiserings-API'en og eksekveringstimen til at være enige.
For en normal React 18 single-page-applikation er den korteste korrekte mentale model: HTML'en opretter containeren; JavaScript finder den container; createRoot tager containeren; root.render tager komponenten. Når disse fire dele er i den rigtige rækkefølge, forsvinder “Target container is not a DOM element” normalt af den rigtige årsag.