Sākums
» Pamatzināšanas
»
Kā novērst kļūdu “Target container is not a DOM element” React 18
Kā novērst kļūdu “Target container is not a DOM element” React 18
Svarīgākais risinājums ir šāds: pārliecinieties, ka vērtība, ko nododat funkcijai createRoot(), ir reāls DOM elements, kas jau eksistē. React 18 standarta klienta ieejas punkts izskatās šādi:
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 />);
Ja document.getElementById('root') atgriež null, vai ja nejauši nododat React elementu, piemēram, <App />, funkcijai createRoot(), React nevar izveidot sakni un var ziņot par kļūdu “Target container is not a DOM element.” React oficiālā createRoot problēmu novēršanas dokumentācija definē šo kļūdu tieši šādos vārdos: vērtība, kas nodota createRoot, nav DOM mezgls.
Šis ceļvedis sākas ar šo visbiežāk sastopamo cēloni, pēc tam aptver laika problēmas, React 18 migrācijas kļūdas, servera renderēšanu, portālus, TypeScript un testēšanas vides, lai jūs varētu apstāties, kad sasniedzat jūsu lietotnei atbilstošo gadījumu.
1. solis: Pierādiet, ko patiesībā nododat funkcijai createRoot()
Pirms konfigurācijas maiņas, reģistrējiet konteineru:
Ja konsolē tiek izvadīts null, React nav tā daļa, kas pirmā neizdevās. Pārlūks neatrada elementu ar šo ID brīdī, kad jūsu kods tika izpildīts. React oficiālā problēmu novēršanas sadaļa norāda uz ID neatbilstību un izpildi pirms DOM mezgla eksistences kā biežiem iemesliem.
Ja konsolē tiek izvadīts kaut kas līdzīgs <div id="root"></div>, tad konteiners eksistē, un jums vajadzētu pāriet uz React API, SSR, portāla vai vides pārbaudēm zemāk.
Attiecas uz: gadījumiem, kad kļūda parādās uzreiz lietotnes starta laikā, īpaši failos main.jsx, index.jsx vai index.tsx.
Darbība: nespēlējiet minējumus. Reģistrējiet precīzo vērtību, kas nodota funkcijai createRoot(). Ja tā ir null, novērsiet iemeslu, kāpēc DOM meklēšana neizdevās, pirms pieskaraties komponentu kodam.
AI ģenerēta ilustrācija par React 18 konteinera kļūdu izstrādātāja konsolē. Tā nav ekrānuzņēmums no reālas lietotnes vai React DevTools.
2. solis: Saskaņojiet HTML ID ar JavaScript meklēšanu
Vienkāršākais reālās dzīves cēlonis ir neatbilstība starp jūsu HTML un JavaScript.
Jūsu HTML var saturēt:
<div id="app"></div>
bet jūsu React ieejas fails meklē:
document.getElementById('root')
Šiem nosaukumiem ir jāsakrīt. Vai nu mainiet marķējumu:
<div id="root"></div>
vai mainiet meklēšanu:
const container = document.getElementById('app');
React pašreizējā createRoot atsauce izmanto standarta piemēru document.getElementById('root'), bet root nav maģisks obligāts ID. Jebkurš reāls DOM elements var tikt izmantots kā saknes konteiners. Svarīgākais nosacījums ir tas, ka elements eksistē un meklēšana to atgriež.
Attiecas uz: gadījumiem, kad nesen mainījāt HTML veidni, migrējāt no Create React App uz Vite vai citu bundleru, ieguldat React esošā servera renderētā lapā vai pārdēvējāt montēšanas elementu.
Darbība: meklējiet projektā gan id="root", gan getElementById('root'). Ja projekts apzināti izmanto citu ID, panāciet, lai HTML un JavaScript sakristu.
AI ģenerēta ilustrācija par atbilstošu id="root" montēšanas elementu. Tas ir konceptuāls koda redaktora skats, nevis ekrānuzņēmums no konkrēta ietvara veidnes.
3. solis: Izmantojiet React 18 saknes API pareizā secībā
React 18 ieviesa createRoot klienta API. Oficiālajā React 18 jaunināšanas ceļvedī ir parādīta migrācija no vecāka ReactDOM.render modeļa uz:
Pārsteidzoši viegla kļūda ir samainīt vietām DOM konteineru un React komponentu:
// Nepareizi
createRoot(<App />);
React skaidri norāda to kā citu biežu cēloni kļūdai “Target container is not a DOM element”. createRoot() saņem DOM mezglu; root.render() saņem React mezglu.
Cita migrācijas kļūda ir mentāli pārnest React 17 parakstu un mēģināt nodot konteineru funkcijai root.render():
React createRoot atsauce dokumentē root.render(reactNode) kā funkciju, kas saņem React mezglu, savukārt konteiners pieder pie createRoot(domNode).
TypeScript: nesajauciet nenulles apgalvojumu ar laika risinājumu
React 18 jaunināšanas ceļvedis parāda createRoot(container!) kā TypeScript formu. Izsaukuma zīme ir kompilācijas laika apgalvojums: tā pasaka TypeScript, ka jūs uzskatāt vērtību par nenullu. Tā nerada trūkstošu HTML elementu izpildes laikā.
Drošāks modelis, kad atkļūdojat, ir:
const container = document.getElementById('root');
if (container === null) {
throw new Error('Expected #root to exist');
}
createRoot(container).render(<App />);
Tas rada noderīgāku lietotnei specifisku kļūdu, ja HTML un JavaScript izklīst.
Attiecas uz: gadījumiem, kad problēma parādījās React 17 → React 18 migrācijas laikā, pēc ieejas faila kopēšanas no cita projekta, vai tikai TypeScript būvējumos, kur ! tika pievienots, lai apklusinātu kompilatora brīdinājumu.
Darbība: pārbaudiet izsaukumu secību: DOM meklēšana → createRoot(container) → root.render(<App />). Atkļūdošanas laikā dodiet priekšroku eksplcitai null pārbaudei, nevis aklai container! apgalvošanai.
AI ģenerēta ilustrācija par aizsargājošu React 18 starta modeli. Kods ir parādīts kā konceptuāls piemērs, nevis kā sagūstīta izvade no reāla projekta.
4. solis: Pārliecinieties, ka jūsu starta kods tiek izpildīts pēc mērķa elementa izveides
ID var būt perfekti uzrakstīts, bet joprojām atgriezt null, ja jūsu skripts tiek izpildīts pirms pārlūks ir parsējis elementu. React problēmu novēršanas dokumentācija īpaši brīdina, ka bundlera skripts nespēj redzēt DOM mezglus, kas parādās vēlāk HTML, ja izpilde notiek pārāk agri.
Tas galvenokārt attiecas uz pielāgotām HTML lapām un vecākām iegulšanas iestatījumiem. Bieži sastopams drošs izkārtojums ir novietot montēšanas elementu pirms skripta:
Ja kontrolējat pielāgotu skriptu, kas var tikt izpildīts pirms parsēšanas pabeigšanas, cita aizsargājoša opcija ir gaidīt 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();
}
Nepievienojiet šo ietvaru automātiski katram React projektam. Mūsdienu bundleri un ietvari parasti pārvalda ieejas skriptu novietojumu un ielādes semantiku jūsu vietā. Ja standarta Vite, Next.js, Remix vai ietvara ģenerēta lietotne pēkšņi sāk rādīt šo kļūdu, vispirms meklējiet mainītu veidni, montēšanas ID, pielāgotu integrāciju vai kodu, kas darbojas ārpus paredzētās pārlūka ieejas punkta.
Attiecas uz: gadījumiem, kad tas pats ID eksistē gala HTML, bet meklēšana starta laikā joprojām ir null, īpaši manuāli saliktā HTML lapā, CMS veidnē, logrīka iegulumā vai trešās puses skripta integrācijā.
Darbība: pārbaudiet faktisko lapas avotu un izpildes secību. Pārliecinieties, ka montēšanas mezgls eksistē pirms koda, kas izsauc createRoot().
AI ģenerēta ilustrācija par DOM gatavības aizsardzību pielāgotai React startēšanai. Tas nav obligāts modelis katrai React 18 lietotnei; izmantojiet to tikai tad, kad starta laiks patiešām ir problēma.
Ja jūsu lapa ir servera renderēta, izmantojiet hydrateRoot vietā
Ir svarīgs nosacījums, kurā derīgs DOM elements nav pietiekams, lai createRoot() būtu pareizais API. Ja konteiners jau satur HTML, ko serverī vai būvēšanas laikā ģenerējis React, React dokumentācija saka izmantot hydrateRoot() nevis 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 />);
Iemesls atšķiras no mērķa konteinera kļūdas. createRoot() pārvalda klienta renderētu sakni un pirmajā renderēšanā notīra esošo HTML šajā saknē. hydrateRoot() piesien React HTML, ko serverī jau bija izveidojis React. Oficiālā createRoot dokumentācija to skaidri norāda kā servera renderēšanas slazdu.
Attiecas uz: gadījumiem, kad jums ir servera renderēts React HTML, statiska ģenerēšana, kas izdala React marķējumu, vai ietvars, kas hidrē HTML pārlūkā.
Darbība: “nelabojiet” SSR, aizstājot servera marķējumu ar tukšu konteineru. Izmantojiet ietvara hidrācijas ieejas punktu vai React hydrateRoot() pēc vajadzības.
Ja tas ir modāļa vai rīka padoma mērķis, jums var būt nepieciešams createPortal, nevis cita sakne
Dažreiz izstrādātāji redz trūkstošu konteineru, mēģinot renderēt modāli, rīka padomu, toast reģionu vai pārklājumu ārpus galvenās lietotnes koka. React dokumentācija saka, ka, ja vēlaties, lai JSX parādītos citur DOM, izmantojiet createPortal(), nevis veidojiet citu sakni tikai šim bērna UI.
import { createPortal } from 'react-dom';
function Modal({ children }) {
const modalRoot = document.getElementById('modal-root');
if (!modalRoot) return null;
return createPortal(children, modalRoot);
}
Oficiālā createPortal dokumentācija saka, ka portāla mērķim jau ir jāeksistē. Tātad portāli var radīt saistītu konteinera problēmu klasi, ja modal-root trūkst, bet arhitektūras risinājums nav obligāti “izsaukt createRoot vēlreiz”.
Attiecas uz: gadījumiem, kad kļūdainais konteiners nav jūsu lietotnes galvenā sakne, bet gan pārklājuma mērķis vai mezgls, kas pārvaldīts ārpus komponenta parastās DOM pozīcijas.
Darbība: saglabājiet vienu parasto lietotnes sakni, ja vien jums patiešām nav nepieciešamas vairākas neatkarīgas saknes. Modāļa stila UI vienā React lietotnē dodiet priekšroku portālam uz esošu DOM mezglu.
Kas notiek, ja kļūda rodas tikai testos?
Tests var neizdoties tā paša fundamentālā iemesla dēļ: paredzētais konteiners nekad netika ievietots testa DOM. Ja jūsu tests manuāli izsauc createRoot(document.getElementById('root')), pārliecinieties, ka testa iestatījums patiešām izveido šo mezglu pirms renderēšanas.
Tomēr daudzas React testēšanas bibliotēkas pārvalda konteinerus jūsu vietā. Ja jau izmantojat testēšanas ietvara render() palīgfunkciju, manuāla React saknes izveide var būt nevajadzīga un padarīt testa iestatījumus trauslākus.
Attiecas uz: gadījumiem, kad izstrāde pārlūkā darbojas, bet Jest, Vitest, JSDOM vai cita testēšanas vide met konteinera kļūdu.
Darbība: pārbaudiet testa DOM iestatījumus, nevis produkcijas index.html. Pārliecinieties, ka mezgls eksistē vidē, kurā kļūdainais kods patiesībā darbojas.
Kas notiek, ja dokuments nav pieejams?
Ja kods, kas izsauc document.getElementById(), tiek izpildīts serverī vai citā nepārlūka vidē, jums ir cita integrācijas problēma. React klienta API react-dom/client ir paredzēti renderēšanai pārlūka DOM mezglos. Servera renderēšana izmanto API no react-dom/server, un ietvari parasti atdala servera un klienta ieejas punktus.
Attiecas uz: gadījumiem, kad kļūda parādās servera puses renderēšanas laikā, Node būvēšanas solī vai kodā, kas kopīgs starp servera un pārlūka bundleriem.
Darbība: pārvietojiet tikai pārlūkam paredzēto saknes izveidi uz klienta ieejas punktu. Ja izmantojat ietvaru, sekojiet tā dokumentētajai klienta/servera robežai, nevis manuāli izsauciet createRoot() no kopīga servera koda.
Ātrās diagnostikas tabula
Ko jūs redzat
Iespējamais cēlonis
Labākā nākamā pārbaude
console.log(container) ir null
ID neatbilstība vai elements vēl nav klāt
Salīdziniet HTML ID un meklēšanu; pārbaudiet skripta laiku
HTML izmanto id="app", kods vaicā root
Montēšanas ID neatbilstība
Padariet abus nosaukumus identiskus
createRoot(<App />)
React elements nodots tur, kur nepieciešams DOM mezgls
Nododiet DOM mezglu createRoot, pēc tam renderējiet <App />
Projekts joprojām izmanto ReactDOM.render pēc React 18 jaunināšanas
Vecs klienta API
Migrējiet uz createRoot, izmantojot React 18 jaunināšanas ceļvedi
Konteiners jau satur servera renderētu React HTML
Nepareiza klienta inicializācijas API
Izmantojiet hydrateRoot
Neizdodas tikai modāļa/rīka padoma mērķis
Trūkstošs portāla mērķis vai nevajadzīga papildu sakne
Izmantojiet createPortal ar esošu DOM mezglu
Neizdodas tikai testi
Testa DOM nekad neizveidoja mērķa elementu
Izveidojiet konteineru testa iestatījumā vai izmantojiet testu bibliotēkas renderētāju
Gala pārbaude: apstipriniet labojumu, nevis slēpjiet kļūdu
Pēc izmaiņu veikšanas pārbaudiet starta ceļu šādā secībā:
Atveriet lapu un pārbaudiet pārlūka konsoli. Mērķa konteinera kļūdai vajadzētu būt pazūdai.
Izpildiet console.log(document.getElementById('root')) un pārliecinieties, ka tas izvada reālu elementu, nevis null.
Pārliecinieties, ka importējat createRoot no react-dom/client React 18 klienta renderētā lietotnē.
Pārliecinieties, ka DOM elements tiek nodots createRoot() un React komponents tiek nodots root.render().
Ja lapa tika renderēta ar React serverī, pārliecinieties, ka klients izmanto hydrateRoot() vietā.
Ja kļūdainais mērķis ir modālis vai rīka padoms, pārliecinieties, ka portāla mērķis eksistē pirms createPortal() izsaukšanas.
Nekonsiderējiet TypeScript nenulles apgalvojumu, opcionālo ķēdēšanu vai catch bloku kā pašu labojumu. Šīs tehnikas var apklusināt kļūdas ceļu, nepiegādājot DOM mezglu, ko React patiesībā nepieciešams. Ilgtspējīgs labojums ir panākt, lai lapas struktūra, inicializācijas API un izpildes laiks sakristu.
Parastai React 18 vienlapas lietotnei īsākais pareizais mentālais modelis ir: HTML izveido konteineru; JavaScript atrod šo konteineru; createRoot saņem konteineru; root.render saņem komponentu. Kad šīs četras daļas ir pareizā secībā, “Target container is not a DOM element” parasti pazūd pareizā iemesla dēļ.