Hem
» Grundläggande kunskap
»
Så här åtgärdar du felet "Target container is not a DOM element" i React 18
Så här åtgärdar du felet "Target container is not a DOM element" i React 18
Den viktigaste åtgärden är denna: se till att värdet du skickar till createRoot() är ett faktiskt DOM-element som redan finns. I React 18 ser den vanliga klientstartpunkten ut så här:
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 />);
Om document.getElementById('root') returnerar null, eller om du av misstag skickar ett React-element som <App /> till createRoot(), kan React inte skapa en rot och kan rapportera "Target container is not a DOM element". Reaktors egen felsökningsdokumentation för createRoot definierar felet exakt i dessa termer: värdet som skickas till createRoot är inte en DOM-nod.
Den här guiden börjar med den högsannolika orsaken, täcker sedan timingproblem, migreringsfel i React 18, serverrendering, portaler, TypeScript och testmiljöer så att du kan sluta när du når fallet som matchar din app.
Steg 1: Bevisa vad du faktiskt skickar till createRoot()
Om konsolen skriver ut null, är det inte React som misslyckades först. Webbläsaren hittade inte ett element med det ID:t när din kod kördes. Reaktors officiella felsökningsavsnitt listar ett ID-mismatch och exekvering innan DOM-noden finns som vanliga orsaker.
Om konsolen skriver ut något som <div id="root"></div>, då finns containern och du bör hoppa fram till React API-, SSR-, portal- eller miljökontrollerna nedan.
Gäller när: felet dyker upp omedelbart vid applikationsstart, särskilt i main.jsx, index.jsx eller index.tsx.
Åtgärd: gissa inte. Logga det exakta värdet som skickas till createRoot(). Om det är null, åtgärda varför DOM-uppslagningen misslyckades innan du rör komponentkoden.
AI-genererad illustration av React 18-containerfelet i en utvecklar-konsol. Det är inte en skärmdump från en riktig applikation eller React DevTools.
Steg 2: Matcha HTML-ID:t med JavaScript-uppslagningen
Den enklaste verkliga orsaken är ett mismatch mellan din HTML och ditt JavaScript.
Din HTML kan innehålla:
<div id="app"></div>
medan din React-startfil frågar efter:
document.getElementById('root')
Dessa namn måste matcha. Ändra antingen markeringen:
<div id="root"></div>
eller ändra uppslagningen:
const container = document.getElementById('app');
Reaktors nuvarande createRoot-referens använder standardexemplet document.getElementById('root'), men root är inte ett magiskt obligatoriskt ID. Vilket riktigt DOM-element som helst kan användas som rotcontainer. Det viktiga villkoret är att elementet finns och att uppslagningen returnerar det.
Gäller när: du nyligen ändrade en HTML-mall, migrerade från Create React App till Vite eller en annan bundler, bäddade in React i en befintlig serverrenderad sida, eller bytte namn på monteringselementet.
Åtgärd: sök i projektet efter både id="root" och getElementById('root'). Om projektet avsiktligt använder ett annat ID, se till att HTML och JavaScript överensstämmer.
AI-genererad illustration av ett matchande id="root"-monteringselement. Det är en konceptuell kodredigerarvy, inte en skärmdump av en specifik ramverksmall.
Steg 3: Använd React 18 rot-API:t i rätt ordning
React 18 introducerade klient-API:t createRoot. Den officiella React 18 uppgraderingsguiden visar migreringen från det äldre ReactDOM.render-mönstret till:
Ett förvånansvärt enkelt misstag är att byta roller mellan DOM-containern och React-komponenten:
// Fel
createRoot(<App />);
React listar uttryckligen detta som en annan vanlig orsak till felet "Target container is not a DOM element". createRoot() tar emot DOM-noden; root.render() tar emot React-noden.
Ett annat migreringsfel är att mentalt behålla React 17-signaturen och försöka skicka containern till root.render():
// Fel mental modell
root.render(<App />, container);
// Korrekt
const root = createRoot(container);
root.render(<App />);
Reaktors createRoot-referens dokumenterar root.render(reactNode) som tar emot React-noden, medan containern tillhör createRoot(domNode).
TypeScript: förväxla inte den icke-null-assertionen med en körningsfix
React 18 uppgraderingsguiden visar createRoot(container!) som en TypeScript-form. Utropstecknet är en kompileringstidsassertion: det säger till TypeScript att du tror att värdet inte är null. Det skapar inte ett saknat HTML-element vid körning.
Ett säkrare mönster när du felsöker är:
const container = document.getElementById('root');
if (container === null) {
throw new Error('Expected #root to exist');
}
createRoot(container).render(<App />);
Detta ger ett mer användbart applikationsspecifikt fel om HTML och JavaScript glider isär.
Gäller när: problemet uppstod under en React 17 → React 18-migrering, efter att ha kopierat en startfil från ett annat projekt, eller endast i TypeScript-byggen där ! lades till för att tysta en kompilatorvarning.
Åtgärd: verifiera anropssekvensen: DOM-uppslagning → createRoot(container) → root.render(<App />). Under felsökning, föredra en explicit null-kontroll framför att blindt asserta container!.
AI-genererad illustration av ett defensivt React 18-startmönster. Koden visas som ett konceptuellt exempel, inte som fångad utdata från ett faktiskt projekt.
Steg 4: Se till att din startkod körs efter att målelementet finns
Ett ID kan vara perfekt stavat och ändå returnera null om ditt skript körs innan webbläsaren har tolkat elementet. Reaktors felsökningsdokumentation varnar specifikt för att ett bundelskript inte kan se DOM-noder som dyker upp senare i HTML:n när exekveringen sker för tidigt.
Detta är främst relevant för anpassade HTML-sidor och äldre inbäddningsinställningar. En vanlig säker layout är att placera monteringselementet före skriptet:
Om du kontrollerar ett anpassat skript som kan köras innan tolkningen är klar, är ett annat defensivt alternativ att vänta 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();
}
Lägg inte till denna wrapper automatiskt till varje React-projekt. Moderna bundlers och ramverk hanterar vanligtvis placering och laddningssemantik för startskript åt dig. Om en standard Vite-, Next.js-, Remix- eller ramverksgenererad app plötsligt utvecklar detta fel, leta först efter en ändrad mall, montering-ID, anpassad integration eller kod som körs utanför den förväntade webbläsarstartpunkten.
Gäller när: samma ID finns i den slutliga HTML:n men uppslagningen är fortfarande null under start, särskilt i en manuellt sammansatt HTML-sida, CMS-mall, widget-inbäddning eller tredjepartsskriptintegration.
Åtgärd: inspektera den faktiska sidkällan och exekveringsordningen. Se till att monteringsnoden finns innan koden som anropar createRoot().
AI-genererad illustration av en DOM-readiness-guard för en anpassad React-bootstrap. Det är inte ett obligatoriskt mönster för varje React 18-app; använd det endast när starttiming faktiskt är problemet.
Om din sida är serverrenderad, använd hydrateRoot istället
Det finns ett viktigt villkor där ett giltigt DOM-element inte är tillräckligt för att göra createRoot() till rätt API. Om containern redan innehåller HTML som genererats av React på servern eller vid byggtid, säger Reaktors dokumentation att du ska använda hydrateRoot() istället för 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 />);
Anledningen är annorlunda än target-container-felet. createRoot() hanterar en klientrenderad rot och rensar befintlig HTML inuti den roten vid den första renderingen. hydrateRoot() fäster React vid HTML som redan producerats av React på servern. Den officiella createRoot-dokumentationen påpekar uttryckligen detta som en serverrenderingsfälla.
Gäller när: du har serverrenderad React HTML, statisk generering som emitterar React-markering, eller ett ramverk som hydrerar HTML i webbläsaren.
Åtgärd: "fixa" inte SSR genom att ersätta servermarkering med en tom container. Använd ramverkets hydreringsstartpunkt eller Reaktors hydrateRoot() som lämpligt.
Om detta är en modal- eller tooltip-mål, kan du behöva createPortal – inte en annan rot
Ibland ser utvecklare en saknad container när de försöker rendera en modal, tooltip, toast-region eller overlay utanför huvudapp-trädet. Reaktors dokumentation säger att när du vill att JSX ska dyka upp någon annanstans i DOM:n, använd createPortal() snarare än att skapa en annan rot bara för den barn-UI:n.
import { createPortal } from 'react-dom';
function Modal({ children }) {
const modalRoot = document.getElementById('modal-root');
if (!modalRoot) return null;
return createPortal(children, modalRoot);
}
Den officiella createPortal-dokumentationen säger att portal-målet måste redan finnas. Så portaler kan producera en relaterad klass av containerproblem om modal-root saknas, men den arkitektoniska fixen är inte nödvändigtvis "anropa createRoot igen".
Gäller när: den misslyckade containern inte är din applikations huvudrot utan en overlay-destination eller en nod som hanteras utanför komponentens normala DOM-position.
Åtgärd: behåll en normal applikationsrot om du inte genuint behöver flera oberoende rötter. För modal-liknande UI inom samma React-applikation, föredra en portal till en befintlig DOM-nod.
Vad händer om felet bara inträffar i tester?
Ett test kan misslyckas av samma grundläggande anledning: den förväntade containern sattes aldrig in i test-DOM:n. Om ditt test manuellt anropar createRoot(document.getElementById('root')), se till att testinställningen faktiskt skapar den noden innan rendering.
Men många React-testbibliotek hanterar containrar åt dig. Om du redan använder ett testramverks render()-hjälpfunktion, kan det vara onödigt att manuellt skapa en React-rot och kan göra testinställningen mer skör.
Gäller när: utveckling fungerar i webbläsaren men Jest, Vitest, JSDOM eller en annan testmiljö kastar containerfelet.
Åtgärd: inspektera testets DOM-inställning, inte produktions-index.html. Bekräfta att noden finns i den miljö där den misslyckade koden faktiskt körs.
Vad händer om document inte är tillgängligt?
Om kod som anropar document.getElementById() exekverar i en server eller annan icke-webbläsarmiljö, har du ett annat integrationsproblem. Reaktors klient-API:er i react-dom/client är designade för att rendera till webbläsar-DOM-noder. Serverrendering använder API:er från react-dom/server, och ramverk separerar normalt server- och klientstartpunkter.
Gäller när: felet dyker upp under server-side rendering, ett Node-byggsteg, eller kod som delas mellan server- och webbläsarbundlar.
Åtgärd: flytta webbläsar-specifik rotskapande till klientstartpunkten. Om du använder ett ramverk, följ dess dokumenterade klient/server-gräns istället för att manuellt anropa createRoot() från delad serverkod.
Snabb diagnos-tabell
Vad du ser
Sannolik orsak
Bästa nästa kontroll
console.log(container) är null
ID-mismatch eller element finns inte ännu
Jämför HTML-ID:t och uppslagningen; inspektera skripttiming
HTML använder id="app", koden frågar efter root
Monterings-ID-mismatch
Gör båda namnen identiska
createRoot(<App />)
React-element skickat där DOM-nod krävs
Skicka DOM-noden till createRoot, rendera sedan <App />
Projektet använder fortfarande ReactDOM.render efter en React 18-uppgradering
Äldre klient-API
Migrera till createRoot med hjälp av React 18 uppgraderingsguiden
Containern innehåller redan serverrenderad React HTML
Fel klientinitierings-API
Använd hydrateRoot
Endast en modal/tooltip-mål misslyckas
Saknad portal-mål eller onödig extra rot
Använd createPortal med en befintlig DOM-nod
Endast tester misslyckas
Test-DOM:n skapade aldrig målelementet
Skapa containern i testinställningen eller använd testbibliotekets renderer
Slutlig verifiering: bekräfta fixen istället för att dölja felet
Efter att ha gjort en ändring, verifiera startvägen i denna ordning:
Öppna sidan och inspektera webbläsarkonsolen. Target-container-felet bör vara borta.
Kör console.log(document.getElementById('root')) och bekräfta att det skriver ut ett riktigt element, inte null.
Bekräfta att du importerar createRoot från react-dom/client i en React 18 klientrenderad app.
Bekräfta att DOM-elementet skickas till createRoot() och React-komponenten skickas till root.render().
Om sidan renderades av React på servern, bekräfta att klienten använder hydrateRoot() istället.
Om den misslyckade destinationen är en modal eller tooltip, bekräfta att portal-målet finns innan du anropar createPortal().
Betrakta inte en TypeScript icke-null-assertion, validerad kedjning eller ett catch-block som fixen i sig. Dessa tekniker kan tysta en felväg utan att tillhandahålla den DOM-nod React faktiskt behöver. Den hållbara fixen är att få sidstrukturen, initierings-API:t och exekveringstiming att överensstämma.
För en normal React 18 single-page-applikation är den kortaste korrekta mentala modellen: HTML:n skapar containern; JavaScript hittar den containern; createRoot tar containern; root.render tar komponenten. När dessa fyra delar är i rätt ordning, försvinner "Target container is not a DOM element" vanligtvis av rätt anledning.