Kako odpraviti napako "Target container is not a DOM element" v React 18

Najpomembnejša rešitev je naslednja: zagotovite, da je vrednost, ki jo posredujete funkciji createRoot(), dejanski DOM element, ki že obstaja. V React 18 običajna vstopna točka odjemalca izgleda takole:

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 />);

Če document.getElementById('root') vrne null ali če pomotoma posredujete React element, kot je <App />, funkciji createRoot(), React ne more ustvariti korena in lahko javi napako “Target container is not a DOM element”. Reactova lastna dokumentacija za odpravljanje težav s createRoot napako definira prav v teh izrazih: vrednost, posredovana funkciji createRoot, ni DOM vozlišče.

Ta vodnik se začne s to najbolj verjetno vzrokom, nato pa obravnava težave s časovnim zaporedjem, napake pri migraciji na React 18, strežniško upodabljanje, portale, TypeScript in testna okolja, da lahko ustavite, ko dosežete primer, ki ustreza vaši aplikaciji.

Korak 1: Dokažite, kaj dejansko posredujete funkciji createRoot()

Pred spreminjanjem konfiguracije zabeležite vsebino spremenljivke container:

const container = document.getElementById('root');
console.log(container);

const root = createRoot(container);

Če konzola izpiše null, React ni del, ki je prvi odpovedal. Brskalnik v trenutku izvajanja kode ni našel elementa s tem ID-jem. Reactov uradni razdelek za odpravljanje težav navaja neskladje ID-jev in izvajanje preden DOM vozlišče obstaja, kot pogoste razloge.

Če konzola izpiše nekaj podobnega <div id="root"></div>, potem container obstaja in preskočite na spodnje preglede React API-ja, SSR, portalov ali okolja.

Velja, ko: se napaka pojavi takoj ob zagonu aplikacije, zlasti v datotekah main.jsx, index.jsx ali index.tsx.

Ukrep: ne ugibajte. Zabeležite točno vrednost, posredovano funkciji createRoot(). Če je null, popravite razlog, zakaj je iskanje po DOM-u spodletelo, preden posegate v kodo komponent.

Ilustracija urejevalnika kode, ki jo je ustvaril AI, prikazuje napako React Target container is not a DOM element
Ilustracija, ki jo je ustvaril AI, prikazuje napako s containerjem v React 18 v razvijalski konzoli. To ni posnetek zaslona iz resnične aplikacije ali React DevTools.

Korak 2: Uskladite ID v HTML s poizvedbo v JavaScriptu

Najpreprostejši dejanski vzrok je neskladje med vašim HTML in JavaScriptom.

Vaš HTML morda vsebuje:

<div id="app"></div>

medtem ko vaša vstopna datoteka React zahteva:

document.getElementById('root')

Ti imeni se morata ujemati. Spremenite bodisi oznako:

<div id="root"></div>

bodisi poizvedbo:

const container = document.getElementById('app');

Trenutna referenca createRoot v Reactu uporablja standardni primer document.getElementById('root'), vendar root ni čarobni obvezni ID. Kot korenski container je mogoče uporabiti katerikoli pravi DOM element. Pomemben pogoj je, da element obstaja in da ga poizvedba vrne.

Velja, ko: ste nedavno spremenili predlogo HTML, migrirali iz Create React App na Vite ali drug zbirnik, vgradili React v obstoječo stran, ki jo upodablja strežnik, ali preimenovali element za namestitev.

Ukrep: v projektu poiščite tako id="root" kot getElementById('root'). Če projekt namenoma uporablja drug ID, uskladite HTML in JavaScript.

Ilustracija urejevalnika kode, ki jo je ustvaril AI, poudarja div z id root v HTML datoteki
Ilustracija, ki jo je ustvaril AI, prikazuje ujemanje elementa za namestitev id="root". To je konceptualni pogled urejevalnika kode, ne posnetek zaslona določene predloge ogrodja.

Korak 3: Uporabite API korena React 18 v pravilnem vrstnem redu

React 18 je uvedel klientski API createRoot. Uradni vodnik za nadgradnjo na React 18 prikazuje migracijo s starejšega vzorca ReactDOM.render na:

import { createRoot } from 'react-dom/client';

const container = document.getElementById('root');
const root = createRoot(container);
root.render(<App />);

Presenetljivo enostavna napaka je zamenjava vlog DOM containerja in React komponente:

// Napačno
createRoot(<App />);

React to eksplicitno navaja kot še en pogost vzrok za napako “Target container is not a DOM element”. Funkcija createRoot() prejme DOM vozlišče; funkcija root.render() prejme React vozlišče.

Druga napaka pri migraciji je mentalno prenašanje podpisa iz React 17 in poskus posredovanja containerja funkciji root.render():

// Napačen mentalni model
root.render(<App />, container);

// Pravilno
const root = createRoot(container);
root.render(<App />);

Referenca createRoot v Reactu dokumentira, da root.render(reactNode) prejme React vozlišče, medtem ko container pripada funkciji createRoot(domNode).

TypeScript: ne zamenjujte ne-nul trditve z rešitvijo v času izvajanja

Vodnik za nadgradnjo na React 18 prikazuje createRoot(container!) kot obliko za TypeScript. Klicaj je trditev ob prevajanju: TypeScriptu pove, da verjamete, vrednost ni null. V času izvajanja ne ustvari manjkajočega HTML elementa.

Varno vzorec, ko razhroščujete, je:

const container = document.getElementById('root');

if (container === null) {
  throw new Error('Expected #root to exist');
}

createRoot(container).render(<App />);

To ustvari bolj uporabno napako, specifično za aplikacijo, če se HTML in JavaScript razideta.

Velja, ko: se je težava pojavila med migracijo iz React 17 v React 18, po kopiranju vstopne datoteke iz drugega projekta ali samo v gradnjah TypeScript, kjer je bil dodan ! za utišanje opozorila prevajalnika.

Ukrep: preverite zaporedje klicev: DOM lookup → createRoot(container) → root.render(<App />). Med razhroščevanjem raje uporabite eksplicitno preverjanje null kot slepo trditev container!.

Ilustracija urejevalnika kode, ki jo je ustvaril AI, prikazuje preverjanje null pred createRoot in root render v React 18
Ilustracija, ki jo je ustvaril AI, prikazuje obrambni vzorec zagona React 18. Koda je prikazana kot konceptualni primer, ne kot zajeta izhodna vsebina dejanskega projekta.

Korak 4: Zagotovite, da se koda za zagon izvede, ko ciljni element že obstaja

ID je lahko pravilno zapisan, a še vedno vrne null, če se vaša skripta izvede, preden je brskalnik razčlenil element. Reactova dokumentacija za odpravljanje težav posebej opozarja, da skripta paketa ne more videti DOM vozlišč, ki se pojavijo kasneje v HTML, če se izvajanje zgodi prezgodaj.

To je predvsem pomembno za prilagojene HTML strani in starejše nastavitve vgradnje. Varen razpored je običajno, da postavite element za namestitev pred skripto:

<body>
  <div id="root"></div>
  <script type="module" src="/src/main.jsx"></script>
</body>

Če nadzorujete prilagojeno skripto, ki se lahko izvede pred zaključkom razčlenjevanja, je druga obrambna možnost počakati 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();
}

Tega ovoja ne dodajajte samodejno vsaki React projektu. Sodobni zbirniki in ogrodja običajno upravljajo postavitev vstopne skripte in semantiko nalaganja namesto vas. Če aplikacija, ustvarjena z Vite, Next.js, Remix ali drugim ogrodjem, nenadoma razvije to napako, najprej poiščite spremenjeno predlogo, ID namestitve, prilagojeno integracijo ali kodo, ki teče zunaj pričakovane vstopne točke brskalnika.

Velja, ko: isti ID obstaja v končnem HTML, a je poizvedba ob zagonu še vedno null, zlasti v ročno sestavljeni HTML strani, predlogi CMS, vgradnji pripomočka ali integraciji skript tretjih oseb.

Ukrep: preglejte dejanski vir strani in vrstni red izvajanja. Zagotovite, da vozlišče za namestitev obstaja pred kodo, ki kliče createRoot().

Ilustracija urejevalnika kode, ki jo je ustvaril AI, prikazuje zaščito DOMContentLoaded pred ustvarjanjem korena React
Ilustracija, ki jo je ustvaril AI, prikazuje zaščito pripravljenosti DOM za prilagojen zagon React. To ni obvezen vzorec za vsako aplikacijo React 18; uporabite ga le, če je časovno zaporedje zagona dejansko težava.

Če je vaša stran upodobljena na strežniku, uporabite hydrateRoot

Obstaja pomemben pogoj, kjer veljaven DOM element ni dovolj, da bi createRoot() postal pravilen API. Če container že vsebuje HTML, ki ga je React ustvaril na strežniku ali ob gradnji, Reactova dokumentacija pravi, da uporabite hydrateRoot() namesto 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 />);

Razlog je drugačen od napake s ciljnimi containerji. createRoot() upravlja korena, upodobljenega na odjemalcu, in ob prvem upodabljanju počisti obstoječi HTML znotraj tega korena. hydrateRoot() priključi React na HTML, ki ga je React že ustvaril na strežniku. Uradna dokumentacija createRoot to eksplicitno navaja kot past strežniškega upodabljanja.

Velja, ko: imate React HTML, upodobljen na strežniku, statično generiranje, ki oddaja React oznake, ali ogrodje, ki hidrira HTML v brskalniku.

Ukrep: ne “popravite” SSR z zamenjavo strežniških oznak s praznim containerjem. Uporabite vstopno točko za hidratacijo ogrodja ali Reactov hydrateRoot(), kot je primerno.

Če je to ciljni element za modalno okno ali pripomoček, boste morda potrebovali createPortal – ne še en koren

Včasih razvijalci vidijo manjkajoč container, ko poskušajo upodobiti modalno okno, pripomoček, območje za obvestila ali prekrivni sloj zunaj glavne drevesne strukture aplikacije. Reactova dokumentacija pravi, da ko želite, da se JSX pojavi drugje v DOM, uporabite createPortal() namesto ustvarjanja še enega korena samo za ta podrejena uporabniški vmesnik.

import { createPortal } from 'react-dom';

function Modal({ children }) {
  const modalRoot = document.getElementById('modal-root');

  if (!modalRoot) return null;

  return createPortal(children, modalRoot);
}

Uradna dokumentacija createPortal pravi, da ciljni element portala že mora obstajati. Torej lahko portali povzročijo sorodno vrsto težave s containerjem, če modal-root manjka, vendar arhitekturna rešitev ni nujno “ponovno klicanje createRoot”.

Velja, ko: odpovedujoči container ni glavni koren vaše aplikacije, ampak cilj prekrivnega sloja ali vozlišče, ki ga upravlja zunaj običajne DOM pozicije komponente.

Ukrep: obdržite en normalni koren aplikacije, razen če resnično potrebujete več neodvisnih korenov. Za uporabniški vmesnik tipa modalnega okna znotraj iste React aplikacije raje uporabite portal na obstoječe DOM vozlišče.

Kaj pa, če se napaka pojavi samo v testih?

Test lahko spodleti iz istega osnovnega razloga: pričakovani container nikoli ni bil vstavljen v testni DOM. Če vaš test ročno kliče createRoot(document.getElementById('root')), zagotovite, da nastavitev testa dejansko ustvari to vozlišče pred upodabljanjem.

beforeEach(() => {
  document.body.innerHTML = '<div id="root"></div>';
});

Vendar mnoge React testne knjižnice upravljajo containerje namesto vas. Če že uporabljate pomožno funkcijo render() testnega ogrodja, je ročno ustvarjanje React korena morda nepotrebno in lahko naredi nastavitev testa bolj krhko.

Velja, ko: razvoj deluje v brskalniku, a Jest, Vitest, JSDOM ali drugo testno okolje vrže napako s containerjem.

Ukrep: preglejte DOM nastavitev testa, ne produkcijskega index.html. Potrdite, da vozlišče obstaja znotraj okolja, kjer se odpovedujoča koda dejansko izvaja.

Kaj pa, če dokument ni na voljo?

Če se koda, ki kliče document.getElementById(), izvaja na strežniku ali v drugem ne-brskalnem okolju, imate drugačno težavo z integracijo. Reactovi klientski API-ji v react-dom/client so zasnovani za upodabljanje v brskalniška DOM vozlišča. Strežniško upodabljanje uporablja API-je iz react-dom/server, ogrodja pa običajno ločijo strežniške in klientske vstopne točke.

Velja, ko: se napaka pojavi med strežniškim upodabljanjem, korakom gradnje Node ali kodo, ki si jo delita strežniški in brskalniški paketi.

Ukrep: premaknite ustvarjanje korena, ki je namenjeno samo brskalniku, v klientsko vstopno točko. Če uporabljate ogrodje, sledite njegovi dokumentirani meji med strežnikom in odjemalcem, namesto da ročno kličete createRoot() iz skupne strežniške kode.

Tabela za hitro diagnozo

Kaj viditeVerjeten vzrokNajboljši naslednji pregled
console.log(container) je nullNeskladje ID ali element še ni prisotenPrimerjajte ID v HTML in poizvedbo; preglejte časovno zaporedje skript
HTML uporablja id="app", koda poizveduje rootNeskladje ID namestitveUskladite oba imena
createRoot(<App />)React element posredovan tam, kjer je zahtevano DOM vozliščePosredujte DOM vozlišče funkciji createRoot, nato upodobite <App />
Projekt še vedno uporablja ReactDOM.render po nadgradnji na React 18Zastareli klientski APIMigrirajte na createRoot z uporabo vodnika za nadgradnjo na React 18
Container že vsebuje React HTML, upodobljen na strežnikuNapačen klientski API za inicializacijoUporabite hydrateRoot
Odpove samo cilj modalnega okna/pripomočkaManjkajoči cilj portala ali nepotreben dodatni korenUporabite createPortal z obstoječim DOM vozliščem
Odpovejo samo testiTestni DOM nikoli ni ustvaril ciljnega elementaUstvarite container v nastavitvi testa ali uporabite upodabljalec testne knjižnice

Končna preverba: potrdite popravilo namesto skrivanja napake

Po spremembi preverite pot zagona v tem vrstnem redu:

  1. Odprite stran in preglejte brskalniško konzolo. Napaka s ciljnimi containerji bi morala izginiti.
  2. Izvedite console.log(document.getElementById('root')) in potrdite, da izpiše pravi element, ne null.
  3. Potrdite, da uvažate createRoot iz react-dom/client v aplikaciji React 18, ki se upodablja na odjemalcu.
  4. Potrdite, da je DOM element posredovan funkciji createRoot() in React komponenta funkciji root.render().
  5. Če je stran upodobil React na strežniku, potrdite, da odjemalec namesto tega uporablja hydrateRoot().
  6. Če je odpovedujoči cilj modalno okno ali pripomoček, potrdite, da cilj portala obstaja pred klicem createPortal().

Ne štejte TypeScriptove ne-nul trditve, opcionalnega veriženja ali bloka catch za samo rešitev. Te tehnike lahko utišajo pot napake, ne da bi zagotovile DOM vozlišče, ki ga React dejansko potrebuje. Trajna rešitev je uskladitev strukture strani, inicializacijskega API-ja in časovnega zaporedja izvajanja.

Za normalno enostransko aplikacijo React 18 je najkrajši pravilen mentalni model: HTML ustvari container; JavaScript najde ta container; createRoot prejme container; root.render prejme komponento. Ko so ti štirje deli v pravilnem vrstnem redu, napaka “Target container is not a DOM element” običajno izgine iz pravega razloga.

Pusti komentar

Kako odpraviti težavo s SSL certifikatom: Unable to Get Local Issuer Certificate v Gitu

Kako odpraviti težavo s SSL certifikatom: Unable to Get Local Issuer Certificate v Gitu

Odpravite napako Git 'unable to get local issuer certificate' z identifikacijo varnostnega ozadja, namestitvijo pravilnega veriga CA in ohranjanjem vklopljene SSL preverjanja.

Kako odpraviti napako omrežnega časovnega prekoraka MongoDB v povezavi Mongoose

Kako odpraviti napako omrežnega časovnega prekoraka MongoDB v povezavi Mongoose

Odpravite napake omrežnega časovnega prekoraka MongoDB v Mongoose z identifikacijo vrste časovnega prekoraka, testiranjem dosegljivosti Atlas ali TCP, popravkom URI in prilagajanjem časovnih omejitev le, ko je to upravičeno.

Kako odpraviti napako Execution Policy Restricted v sistemu Windows PowerShell

Kako odpraviti napako Execution Policy Restricted v sistemu Windows PowerShell

Odpravite napako izvajalne politike Restricted v PowerShellu tako, da preverite obseg in skupinsko politiko, nato izberete RemoteSigned, Unblock-File ali začasno možnost seje.

Kako odpraviti napako npm ERR! code ERESOLVE zaradi konflikta odvisnosti vrstnikov

Kako odpraviti napako npm ERR! code ERESOLVE zaradi konflikta odvisnosti vrstnikov

Odpravite konflikte odvisnosti vrstnikov npm ERESOLVE tako, da identificirate nezdružljiv razpon paketov, uskladite različice, uporabite ukaze npm explain in npm ls ter uporabljate legacy-peer-deps ali force le kot nadzorovane rezervne možnosti.

Kako odpraviti napako pri povezavi Redis na 127.0.0.1:6379

Kako odpraviti napako pri povezavi Redis na 127.0.0.1:6379

Odpravite napake zavrnjene povezave Redis na 127.0.0.1:6379 s preverjanjem strežnika, vrat, Docker omrežja, redis.conf, preverjanja pristnosti in TLS.

Kako odpraviti notranjo napako 500 v strežniških komponentah Next.js

Kako odpraviti notranjo napako 500 v strežniških komponentah Next.js

Odpravite napake 500 v strežniških komponentah Next.js tako, da sledite strežniškim dnevnikom, preverite pridobivanje podatkov in spremenljivke okolja, obravnavate napake ter preverite produkcijsko gradnjo.

Kako odpraviti napako CrashLoopBackOff v Kubernetesu v lokalnem okolju Minikube

Kako odpraviti napako CrashLoopBackOff v Kubernetesu v lokalnem okolju Minikube

Diagnostika in odpravljanje napake CrashLoopBackOff v Kubernetesu v lokalnem okolju Minikube s preverjanjem stanja poda, prejšnjih dnevnikov, razlogov za izhod, sond, konfiguracije, omejitev pomnilnika in zdravja klastra.

Kako popraviti ustavljen pogon Docker Desktop v sistemu Windows 11

Kako popraviti ustavljen pogon Docker Desktop v sistemu Windows 11

Popravite napako 'Engine stopped' v Docker Desktopu na Windows 11 s preverjanjem stanja Dockerja, posodobitvijo in ponovnim zagonom WSL 2, preverjanjem virtualizacije ter uporabo diagnostike pred ponastavitvijo.

Kako odpraviti napako Uncaught ReferenceError: process is not defined v Vite

Kako odpraviti napako Uncaught ReferenceError: process is not defined v Vite

Odpravite napako 'process is not defined' v Vite tako, da zamenjate uporabo process.env v slogu Node.js, pravilno konfigurirate spremenljivke VITE_ in preverite odvisnosti.

Kako odpraviti napako “PyTorch CUDA Out of Memory” med usposabljanjem modela

Kako odpraviti napako “PyTorch CUDA Out of Memory” med usposabljanjem modela

Odpravite napake PyTorch CUDA out-of-memory s praktičnim postopkom: izmerite pomnilnik GPU, zmanjšajte delovni nabor, uporabite AMP in akumulacijo, shranite aktivacije v kontrolne točke in prilagodite dodeljevalnik le, ko je to potrebno.