Domov
» Osnovno znanje
»
Kako odpraviti napako "Target container is not a DOM element" v React 18
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:
Č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, 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, 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:
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():
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, 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:
Č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, 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.
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 vidite
Verjeten vzrok
Najboljši naslednji pregled
console.log(container) je null
Neskladje ID ali element še ni prisoten
Primerjajte ID v HTML in poizvedbo; preglejte časovno zaporedje skript
HTML uporablja id="app", koda poizveduje root
Neskladje ID namestitve
Uskladite oba imena
createRoot(<App />)
React element posredovan tam, kjer je zahtevano DOM vozlišče
Posredujte DOM vozlišče funkciji createRoot, nato upodobite <App />
Projekt še vedno uporablja ReactDOM.render po nadgradnji na React 18
Zastareli klientski API
Migrirajte na createRoot z uporabo vodnika za nadgradnjo na React 18
Container že vsebuje React HTML, upodobljen na strežniku
Napačen klientski API za inicializacijo
Uporabite hydrateRoot
Odpove samo cilj modalnega okna/pripomočka
Manjkajoči cilj portala ali nepotreben dodatni koren
Uporabite createPortal z obstoječim DOM vozliščem
Odpovejo samo testi
Testni DOM nikoli ni ustvaril ciljnega elementa
Ustvarite 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:
Odprite stran in preglejte brskalniško konzolo. Napaka s ciljnimi containerji bi morala izginiti.
Izvedite console.log(document.getElementById('root')) in potrdite, da izpiše pravi element, ne null.
Potrdite, da uvažate createRoot iz react-dom/client v aplikaciji React 18, ki se upodablja na odjemalcu.
Potrdite, da je DOM element posredovan funkciji createRoot() in React komponenta funkciji root.render().
Če je stran upodobil React na strežniku, potrdite, da odjemalec namesto tega uporablja hydrateRoot().
Č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.