Kaip ištaisyti klaidą „Target container is not a DOM element“ React 18

Svarbiausias sprendimas yra šis: įsitikinkite, kad į createRoot() perduodama reikšmė yra tikras DOM elementas, kuris jau egzistuoja. React 18 įprasta kliento pradinė vieta atrodo taip:

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

Jei document.getElementById('root') grąžina null, arba jei netyčia perduodate React elementą, pvz., <App />, į createRoot(), React negali sukurti šaknies ir gali pranešti apie klaidą „Target container is not a DOM element“. React createRoot trikčių šalinimo dokumentacija apibrėžia šią klaidą būtent taip: į createRoot perduota reikšmė nėra DOM mazgas.

Šis vadovas prasideda nuo šios didelės tikimybės priežasties, tada aptariami laiko problemos, React 18 migracijos klaidos, serverio atvaizdavimas, portalai, TypeScript ir testavimo aplinkos, kad galėtumėte sustoti, kai rasite atvejį, atitinkantį jūsų programą.

1 žingsnis: Įrodykite, ką iš tikrųjų perduodate į createRoot()

Prieš keisdami konfigūraciją, užregistruokite konteinerį:

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

const root = createRoot(container);

Jei konsolėje atspausdinama null, React nėra ta dalis, kuri pirmiausia nepavyko. Naršyklė nerado elemento su tuo ID tuo metu, kai vyko jūsų kodas. Oficiali React trikčių šalinimo skiltis nurodo ID neatitikimą ir vykdymą prieš egzistuojant DOM mazgui kaip dažnas priežastis.

Jei konsolėje atspausdinama kažkas panašaus į <div id="root"></div>, tuomet konteineris egzistuoja ir turėtumėte pereiti prie žemiau pateiktų React API, SSR, portalo ar aplinkos patikrinimų.

Taikoma, kai: klaida atsiranda iškart paleidus programą, ypač main.jsx, index.jsx arba index.tsx.

Veiksmas: nespėliokite. Užregistruokite tikslią reikšmę, perduodamą į createRoot(). Jei ji yra null, ištaisykite, kodėl DOM paieška nepavyko, prieš liesdami komponento kodą.

Dirbtiniu intelektu sugeneruotas kodo redaktoriaus iliustracija, rodanti React klaidą Target container is not a DOM element
Dirbtiniu intelektu sugeneruota React 18 konteinerio klaidos iliustracija kūrėjo konsolėje. Tai nėra tikros programos ar React DevTools ekrano kopija.

2 žingsnis: Suderinkite HTML ID su JavaScript paieška

Paprasta reali priežastis yra neatitikimas tarp jūsų HTML ir JavaScript.

Jūsų HTML gali būti:

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

o jūsų React pradinis failas prašo:

document.getElementById('root')

Šie pavadinimai turi sutapti. Pakeiskite žymėjimą:

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

arba pakeiskite paiešką:

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

React dabartinė createRoot nuoroda naudoja standartinį pavyzdį document.getElementById('root'), tačiau root nėra magiškas privalomas ID. Bet kuris tikras DOM elementas gali būti naudojamas kaip šakninis konteineris. Svarbi sąlyga yra ta, kad elementas egzistuotų ir paieška jį grąžintų.

Taikoma, kai: neseniai keitėte HTML šabloną, migruojate iš Create React App į Vite ar kitą pakuočių rinktuvą, integruojate React į esamą serverio atvaizduotą puslapį arba pervadinote montavimo elementą.

Veiksmas: ieškokite projekte tiek id="root", tiek getElementById('root'). Jei projektas sąmoningai naudoja kitą ID, suderinkite HTML ir JavaScript.

Dirbtiniu intelektu sugeneruotas kodo redaktoriaus iliustracija, paryškinanti div su id root HTML faile
Dirbtiniu intelektu sugeneruota atitinkančio id="root" montavimo elemento iliustracija. Tai konceptualus kodo redaktoriaus vaizdas, o ne konkretaus karkaso šablono ekrano kopija.

3 žingsnis: Naudokite React 18 šaknies API teisinga tvarka

React 18 pristatė createRoot kliento API. Oficialus React 18 atnaujinimo vadovas rodo migraciją iš senesnio ReactDOM.render modelio į:

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

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

Stebėtinai lengva klaida yra supainioti DOM konteinerio ir React komponento vaidmenis:

// Neteisingai
createRoot(<App />);

React aiškiai nurodo tai kaip kitą dažną klaidos „Target container is not a DOM element“ priežastį. createRoot() gauna DOM mazgą; root.render() gauna React mazgą.

Kita migracijos klaida yra protu perkelti React 17 funkcijos parašą ir bandyti perduoti konteinerį į root.render():

// Neteisingas protinis modelis
root.render(<App />, container);

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

React createRoot nuoroda dokumentuoja root.render(reactNode) kaip priimantį React mazgą, o konteineris priklauso createRoot(domNode).

TypeScript: nemaišykite ne-null teiginio su vykdymo laiko pataisymu

React 18 atnaujinimo vadovas rodo createRoot(container!) kaip TypeScript formą. Šauktinis yra kompiliavimo laiko teiginys: jis nurodo TypeScript, kad manote, jog reikšmė nėra null. Jis nesukuria trūkstamo HTML elemento vykdymo metu.

Saugesnis modelis derinant yra:

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

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

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

Tai sukuria naudingesnę konkrečiai programai skirtą klaidą, jei HTML ir JavaScript išsiskiria.

Taikoma, kai: problema atsirado migruojant iš React 17 į React 18, nukopijavus pradinį failą iš kito projekto arba tik TypeScript kompiliacijose, kur ! buvo pridėtas norint nutildyti kompiliatoriaus įspėjimą.

Veiksmas: patikrinkite kvietimų seką: DOM paieška → createRoot(container) → root.render(<App />). Derinant metu pirmenybę teikite aiškiam null patikrinimui, o ne aklai teigiant container!.

Dirbtiniu intelektu sugeneruotas kodo redaktoriaus iliustracija, rodanti null patikrinimą prieš createRoot ir root render React 18
Dirbtiniu intelektu sugeneruota gynybinio React 18 paleidimo modelio iliustracija. Kodas pateikiamas kaip konceptualus pavyzdys, o ne kaip sugautas išvesties rezultatas iš tikro projekto.

4 žingsnis: Įsitikinkite, kad paleidimo kodas vykdomas po to, kai tikslinis elementas egzistuoja

ID gali būti tobulai parašytas ir vis tiek grąžinti null, jei jūsų skriptas veikia prieš naršyklei išanalizavus elementą. React trikčių šalinimo dokumentai konkrečiai perspėja, kad paketo skriptas nemato DOM mazgų, kurie atsiranda vėliau HTML, kai vykdymas įvyksta per anksti.

Tai daugiausia susiję su tinkintais HTML puslapiais ir senesnėmis integravimo sąrankomis. Dažnas saugus išdėstymas yra pastatyti montavimo elementą prieš skriptą:

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

Jei kontroliuojate tinkintą skriptą, kuris gali veikti prieš baigiantis analizavimui, kita gynybinė parinktis yra laukti 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();
}

Neprievirkite šio apvalkalo automatiškai kiekvienam React projektui. Šiuolaikiniai pakuočių rinktuvai ir karkasai paprastai valdo pradinio skripto vietą ir įkėlimo semantiką už jus. Jei standartinė Vite, Next.js, Remix ar karkaso sugeneruota programa staiga pradeda rodyti šią klaidą, pirmiausia ieškokite pakeisto šablono, montavimo ID, tinkintos integracijos arba kodo, veikiančio už tikėtinos naršyklės pradinės vietos.

Taikoma, kai: tas pats ID egzistuoja galutiniame HTML, tačiau paieška paleidimo metu vis tiek yra null, ypač rankiniu būdu surinktuose HTML puslapiuose, CMS šablonuose, valdiklių įterpimuose ar trečiųjų šalių skriptų integracijose.

Veiksmas: apžiūrėkite tikrąjį puslapio šaltinį ir vykdymo tvarką. Įsitikinkite, kad montavimo mazgas egzistuoja prieš kodą, kuris kviečia createRoot().

Dirbtiniu intelektu sugeneruotas kodo redaktoriaus iliustracija, rodanti DOMContentLoaded apsaugą prieš kuriant React šaknį
Dirbtiniu intelektu sugeneruota DOM paruošimo apsaugos iliustracija tinkintam React paleidimui. Tai nėra privalomas modelis kiekvienai React 18 programai; naudokite jį tik tada, kai paleidimo laikas iš tikrųjų yra problema.

Jei jūsų puslapis atvaizduojamas serveryje, naudokite hydrateRoot vietoj to

Yra svarbi sąlyga, kai galiojantis DOM elementas nėra pakankamas, kad createRoot() būtų teisingas API. Jei konteineris jau turi HTML, kurį sugeneravo React serveryje arba kūrimo metu, React dokumentacija nurodo naudoti hydrateRoot() vietoj 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 />);

Priežastis skiriasi nuo tikslinio konteinerio klaidos. createRoot() valdo kliento atvaizduotą šaknį ir pirmojo atvaizdavimo metu išvalo esamą HTML toje šaknyje. hydrateRoot() prijungia React prie HTML, kurį serveryje jau sukūrė React. Oficiali createRoot dokumentacija tai aiškiai nurodo kaip serverio atvaizdavimo spąstą.

Taikoma, kai: turite serveryje atvaizduotą React HTML, statinį generavimą, kuris išskiria React žymėjimą, arba karkasą, kuris hidrata HTML naršyklėje.

Veiksmas: ne „taisykite“ SSR pakeisdami serverio žymėjimą tuščiu konteineriu. Naudokite karkaso hidratacijos pradinę vietą arba React hydrateRoot(), jei tinkama.

Jei tai modalo ar patarimo tikslas, gali prireikti createPortal, o ne kitos šaknies

Kartais kūrėjai mato trūkstamą konteinerį bandydami atvaizduoti modalą, patarimą, pranešimų sritį ar perdangą už pagrindinės programos medžio. React dokumentai teigia, kad norint, jog JSX atsirastų kitoje DOM vietoje, naudokite createPortal(), o ne kurkite kitą šaknį tik tam vaikų UI.

import { createPortal } from 'react-dom';

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

  if (!modalRoot) return null;

  return createPortal(children, modalRoot);
}

Oficiali createPortal dokumentacija teigia, kad portalo tikslas turi jau egzistuoti. Taigi portalai gali sukelti susijusią konteinerio problemų klasę, jei modal-root trūksta, tačiau architekūrinis sprendimas nebūtinai yra „vėl iškviesti createRoot“.

Taikoma, kai: nepavykstantis konteineris nėra jūsų programos pagrindinė šaknis, o perdangos tikslas arba mazgas, valdomas už komponento įprastos DOM padėties.

Veiksmas: laikykitės vienos įprastos programos šaknies, nebent jums iš tikrųjų reikia kelių nepriklausomų šaknų. Modalinio tipo UI toje pačioje React programoje pirmenybę teikite portalui į esamą DOM mazgą.

Ką daryti, jei klaida kyla tik testuose?

Testas gali nepavykti dėl tos pačios esminės priežasties: tikėtinas konteineris niekada nebuvo įterptas į testavimo DOM. Jei jūsų testas rankiniu būdu kviečia createRoot(document.getElementById('root')), įsitikinkite, kad testavimo sąranka iš tikrųjų sukuria tą mazgą prieš atvaizduojant.

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

Tačiau daugelis React testavimo bibliotekų valdo konteinerius už jus. Jei jau naudojate testavimo karkaso render() pagalbą, rankinis React šaknies kūrimas gali būti nereikalingas ir padaryti testavimo sąranką trapesnę.

Taikoma, kai: kūrimas veikia naršyklėje, tačiau Jest, Vitest, JSDOM ar kita testavimo aplinka meta konteinerio klaidą.

Veiksmas: apžiūrėkite testo DOM sąranką, o ne gamybos index.html. Patvirtinkite, kad mazgas egzistuoja aplinkoje, kurioje iš tikrųjų veikia nepavykęs kodas.

Ką daryti, jei dokumentas neprieinamas?

Jei kodas, kviečiantis document.getElementById(), vykdomas serveryje ar kitoje ne naršyklės aplinkoje, turite kitokią integracijos problemą. React kliento API react-dom/client yra sukurti atvaizduoti į naršyklės DOM mazgus. Serverio atvaizdavimas naudoja API iš react-dom/server, o karkasai paprastai atskiria serverio ir kliento pradines vietas.

Taikoma, kai: klaida atsiranda serverio pusės atvaizdavimo metu, Node kūrimo žingsnyje arba kode, bendrinamame tarp serverio ir naršyklės paketų.

Veiksmas: perkelti tik naršyklei skirtą šaknies kūrimą į kliento pradinę vietą. Jei naudojate karkasą, laikykitės jo dokumentuotos kliento/serverio ribos, o ne rankiniu būdu kvieskite createRoot() iš bendro serverio kodo.

Greitos diagnostikos lentelė

Ką matoteTikėtina priežastisGeriausias kitas patikrinimas
console.log(container) yra nullID neatitikimas arba elementas dar nėraPalyginkite HTML ID ir paiešką; apžiūrėkite skripto laiką
HTML naudoja id="app", kodas užklauso rootMontavimo ID neatitikimasSuderinkite abu pavadinimus
createRoot(<App />)React elementas perduotas ten, kur reikalingas DOM mazgasPerduokite DOM mazgą į createRoot, tada atvaizduokite <App />
Projektas vis dar naudoja ReactDOM.render po React 18 atnaujinimoPaveldėtas kliento APIMigruokite į createRoot naudodami React 18 atnaujinimo vadovą
Konteineryje jau yra serveryje atvaizduoto React HTMLNeteisingas kliento inicializavimo APINaudokite hydrateRoot
Nepavyksta tik modalas/patarimo tikslasTrūkstamas portalo tikslas arba nereikalinga papildoma šaknisNaudokite createPortal su esamu DOM mazgu
Nepavyksta tik testaiTestavimo DOM niekada nesukūrė tikslinio elementoSukurkite konteinerį testų sąrankoje arba naudokite testų bibliotekos atvaizduotuvą

Galutinis patikrinimas: patvirtinkite pataisymą, o ne paslėpkite klaidą

Po pakeitimo patvirtinkite paleidimo kelią šia tvarka:

  1. Atidarykite puslapį ir apžiūrėkite naršyklės konsolę. Tikslinio konteinerio klaida turėtų dingti.
  2. Vykdykite console.log(document.getElementById('root')) ir patvirtinkite, kad atspausdinamas tikras elementas, o ne null.
  3. Patvirtinkite, kad importuojate createRoot iš react-dom/client React 18 kliento atvaizduotoje programoje.
  4. Patvirtinkite, kad DOM elementas perduodamas į createRoot(), o React komponentas perduodamas į root.render().
  5. Jei puslapį serveryje atvaizdavo React, patvirtinkite, kad klientas vietoj to naudoja hydrateRoot().
  6. Jei nepavykstantis tikslas yra modalas ar patarimas, patvirtinkite, kad portalo tikslas egzistuoja prieš kviečiant createPortal().

Nelaikykite TypeScript ne-null teiginio, pasirinktinės grandinės ar catch bloko pačiu savaime sprendimu. Šios technikos gali nutildyti klaidos kelią nepateikdamos DOM mazgo, kurio React iš tikrųjų reikia. Ilgalaikis sprendimas yra suderinti puslapio struktūrą, inicializavimo API ir vykdymo laiką.

Įprastai React 18 vieno puslapio programai trumpiausias teisingas protinis modelis yra: HTML sukuria konteinerį; JavaScript randa tą konteinerį; createRoot priima konteinerį; root.render priima komponentą. Kai keturios dalys yra teisinga tvarka, „Target container is not a DOM element“ paprastai dingsta dėl teisingos priežasties.

Palikti komentarą

Kaip ištaisyti klaidą „Prisma Client has not been generated yet“

Kaip ištaisyti klaidą „Prisma Client has not been generated yet“

Ištaisykite „Prisma Client“ nesugeneravimo klaidą patikrinę generatorių, schemą, išvesties kelią, importus, versijas, monorepo sąranką ir diegimo kūrimo veiksmus.

Kaip išspręsti SSL sertifikato problemą: „Unable to Get Local Issuer Certificate“ Git

Kaip išspręsti SSL sertifikato problemą: „Unable to Get Local Issuer Certificate“ Git

Ištaisykite Git klaidą „unable to get local issuer certificate“ nustatydami pasitikėjimo šaltinį, įdiegdami tinkamą CA grandinę ir palikdami įjungtą SSL patikrą.

Kaip išspręsti MongoDB tinklo laiko limito klaidą Mongoose jungtyje

Kaip išspręsti MongoDB tinklo laiko limito klaidą Mongoose jungtyje

Ištaisykite MongoDB tinklo laiko limito klaidas Mongoose nustatydami laiko limito tipą, patikrindami Atlas arba TCP pasiekiamumą, koreguodami URI ir tikslindami laiko limitus tik tada, kai tai pagrįsta.

Kaip išspręsti „Execution Policy Restricted“ klaidą Windows PowerShell

Kaip išspręsti „Execution Policy Restricted“ klaidą Windows PowerShell

Ištaisykite PowerShell vykdymo politikos „Restricted“ klaidą patikrindami sritį ir grupės politiką, tada pasirinkdami RemoteSigned, Unblock-File arba laikiną sesijos parinktį.

Kaip išspręsti npm ERR! code ERESOLVE peer dependency konfliktą

Kaip išspręsti npm ERR! code ERESOLVE peer dependency konfliktą

Ištaisykite npm ERESOLVE peer dependency konfliktus nustatydami nesuderinamą paketo diapazoną, suderindami versijas, naudodami komandas npm explain ir npm ls, bei laikydami legacy-peer-deps arba force tik kontroliuojamais atsarginiais variantais.

Kaip ištaisyti Redis prisijungimo prie 127.0.0.1:6379 klaidą

Kaip ištaisyti Redis prisijungimo prie 127.0.0.1:6379 klaidą

Ištaisykite Redis prisijungimo atmetimo klaidas adresu 127.0.0.1:6379 tikrindami serverį, prievadą, Docker tinklą, redis.conf, autentifikaciją ir TLS.

Kaip ištaisyti vidinę 500 klaidą Next.js Server Components

Kaip ištaisyti vidinę 500 klaidą Next.js Server Components

Ištaisykite Next.js Server Component 500 klaidas stebėdami serverio žurnalus, tikrindami duomenų gavimą ir aplinkos kintamuosius, apdorodami klaidas ir patikrindami gamybinį sukūrimą.

Kaip išspręsti Kubernetes CrashLoopBackOff klaidą vietiniame Minikube

Kaip išspręsti Kubernetes CrashLoopBackOff klaidą vietiniame Minikube

Diagnozuokite ir ištaisykite Kubernetes CrashLoopBackOff klaidą vietiniame Minikube tikrindami pod būseną, ankstesnius žurnalus, išėjimo priežastis, zondas, konfigūraciją, atminties apribojimus ir klasterio sveikatą.

Kaip išspręsti „Docker Desktop Engine Stopped“ klaidą sistemoje Windows 11

Kaip išspręsti „Docker Desktop Engine Stopped“ klaidą sistemoje Windows 11

Ištaisykite „Docker Desktop Engine Stopped“ klaidą sistemoje Windows 11 tikrindami Docker būseną, atnaujindami ir paleisdami iš naujo WSL 2, tikrindami virtualizaciją bei naudodami diagnostiką prieš atstatymą.

Kaip ištaisyti klaidą „Uncaught ReferenceError: process is not defined“ naudojant Vite

Kaip ištaisyti klaidą „Uncaught ReferenceError: process is not defined“ naudojant Vite

Ištaisykite Vite klaidą „process is not defined“ pakeisdami Node stiliaus process.env naudojimą, teisingai sukonfigūruodami VITE_ kintamuosius ir patikrindami priklausomybes.