Avastage Reacti `createPortal` funktsiooni võimsus, et hallata keerukaid kasutajaliideseid, modaalaknaid, tööriistavihjeid ja ületada CSS-i z-indeksi piiranguid.
Kasutajaliidese kihtide valdamine: Sügav sukeldumine Reacti `createPortal` funktsiooni
Kaasaegses veebiarenduses on sujuvate ja intuitiivsete kasutajaliideste loomine esmatähtis. Tihti hõlmab see elementide kuvamist, mis peavad välja murdma oma vanemkomponendi DOM-hierarhiast. Mõelge modaaldialoogidele, teavitusribadele, tööriistavihjetele või isegi keerukatele kontekstimenüüdele. Need kasutajaliidese elemendid vajavad sageli erilist käsitlemist, et tagada nende korrektne renderdamine, asetudes teiste sisuosade peale ilma CSS-i z-index'i virnastamiskontekstide sekkumiseta.
React pakub oma pidevas arengus just selle väljakutse jaoks võimsa lahenduse: createPortal funktsiooni. See react-dom'i kaudu kättesaadav funktsioon võimaldab teil renderdada alamkomponente DOM-i sõlme, mis eksisteerib väljaspool tavapärast Reacti komponendi hierarhiat. See blogipostitus on põhjalik juhend createPortal'i mõistmiseks ja tõhusaks kasutamiseks, uurides selle põhikontseptsioone, praktilisi rakendusi ja parimaid praktikaid globaalsele arendajaskonnale.
Mis on `createPortal` ja miks seda kasutada?
Oma olemuselt on React.createPortal(child, container) funktsioon, mis renderdab Reacti komponendi (child) teise DOM-i sõlme (container) kui see, mis on Reacti puus selle Reacti komponendi vanemaks.
Vaatame parameetrid lähemalt:
child: See on Reacti element, string või fragment, mida soovite renderdada. Sisuliselt on see see, mida tavaliselt tagastaksite komponendirendermeetodist.container: See on DOM-element, mis eksisteerib teie dokumendis. See on sihtmärk, kuhuchildlisatakse.
Probleem: DOM-i hierarhia ja CSS-i virnastamiskontekstid
Mõelgem tavalisele stsenaariumile: modaaldialoog. Modaalaknad on tavaliselt mõeldud kuvamiseks kõige muu sisu peal lehel. Kui renderdate modaalakna komponendi otse teise komponendi sees, millel on piirav overflow: hidden stiil või spetsiifiline z-index väärtus, võib modaalaken olla kärbitud või valesti paigutatud. See on tingitud DOM-i hierarhilisest olemusest ja CSS-i z-index'i virnastamiskonteksti reeglitest.
Elemendi z-index väärtus mõjutab selle virnastamisjärjekorda ainult sama virnastamiskonteksti piires olevate sõsarelementide suhtes. Kui esivanem-element loob uue virnastamiskonteksti (nt omades position väärtust, mis erineb static'ist, ja z-index'it), piirduvad selle esivanema sees renderdatud lapsed selle kontekstiga. See võib põhjustada frustreerivaid paigutusprobleeme, kus teie kavandatud kiht on maetud teiste elementide alla.
Lahendus: `createPortal` appi
createPortal lahendab selle elegantselt, murdes visuaalse seose komponendi asukoha vahel Reacti puus ja selle asukoha vahel DOM-i puus. Saate renderdada komponendi portaali sees ja see lisatakse otse DOM-i sõlme, mis on body sõsar või laps, möödudes seega problemaatilistest esivanemate virnastamiskontekstidest.
Kuigi portaal renderdab oma lapse teise DOM-i sõlme, käitub see siiski nagu tavaline Reacti komponent teie Reacti puus. See tähendab, et sündmuste levimine toimib ootuspäraselt: kui sündmusekäsitleja on lisatud portaali renderdatud komponendile, levib sündmus endiselt üles läbi Reacti komponendi hierarhia, mitte ainult DOM-i hierarhia.
`createPortal`'i peamised kasutusjuhud
createPortal'i mitmekülgsus muudab selle asendamatuks tööriistaks erinevate kasutajaliidese mustrite jaoks:
1. Modaalaknad ja dialoogid
See on ehk kõige levinum ja kaalukam kasutusjuht. Modaalaknad on loodud kasutaja töövoo katkestamiseks ja tähelepanu nõudmiseks. Nende renderdamine otse komponendi sees võib põhjustada virnastamiskonteksti probleeme.
Näidisstsenaarium: Kujutage ette e-kaubanduse rakendust, kus kasutajad peavad tellimuse kinnitama. Kinnitusmodaal peaks ilmuma kõige muu peale lehel.
Rakendamise idee:
- Looge oma
public/index.htmlfailis spetsiaalne DOM-element (või looge see dünaamiliselt). Levinud praktika on omada<div id="modal-root"></div>, mis on sageli paigutatud<body>sildi lõppu. - Hankige oma Reacti rakenduses viide sellele DOM-i sõlmele.
- Kui teie modaalakna komponent käivitatakse, kasutage
ReactDOM.createPortal, et renderdada modaalakna sisumodal-rootDOM-i sõlme.
Koodilõik (kontseptuaalne):
// App.js
import React from 'react';
import Modal from './Modal';
function App() {
const [isModalOpen, setIsModalOpen] = React.useState(false);
return (
Welcome to Our Global Store!
{isModalOpen && (
setIsModalOpen(false)}>
Confirm Your Purchase
Are you sure you want to proceed?
)}
);
}
export default App;
// Modal.js
import React from 'react';
import ReactDOM from 'react-dom';
const modalRoot = document.getElementById('modal-root');
function Modal({ children, onClose }) {
// Loome DOM-elemendi, kuhu modaali sisu paigutada
const element = document.createElement('div');
React.useEffect(() => {
// Lisame elemendi modaali juurele, kui komponent on laetud
modalRoot.appendChild(element);
// Koristame, eemaldades elemendi, kui komponent eemaldatakse
return () => {
modalRoot.removeChild(element);
};
}, [element]);
return ReactDOM.createPortal(
{children}
,
element // Renderdame meie loodud elementi
);
}
export default Modal;
See lähenemine tagab, et modaalaken on modal-root'i otsene laps, mis on tavaliselt lisatud body'le, möödudes seega kõigist vahepealsetest virnastamiskontekstidest.
2. Tööriistavihjed ja hüpikaknad
Tööriistavihjed ja hüpikaknad on väikesed kasutajaliidese elemendid, mis ilmuvad, kui kasutaja suhtleb teise elemendiga (nt liigub hiirega üle nupu või klõpsab ikoonil). Ka need peavad ilmuma muu sisu peale, eriti kui käivitav element on pesastatud sügavale keerulisse paigutusse.
Näidisstsenaarium: Rahvusvahelises koostööplatvormis liigub kasutaja hiirega üle meeskonnaliikme avatari, et näha tema kontaktandmeid ja saadavuse staatust. Tööriistavihje peab olema nähtav sõltumata avatari vanemkonteineri stiilist.
Rakendamise idee: Sarnaselt modaalakendele saate luua portaali tööriistavihjete renderdamiseks. Levinud muster on kinnitada tööriistavihje ühisele portaali juurele või isegi otse body'le, kui teil pole spetsiifilist portaali konteinerit.
Koodilõik (kontseptuaalne):
// Tooltip.js
import React from 'react';
import ReactDOM from 'react-dom';
function Tooltip({ children, targetElement }) {
if (!targetElement) return null;
// Renderdame tööriistavihje sisu otse body-sse
return ReactDOM.createPortal(
{children}
,
document.body
);
}
// Vanemkomponent, mis käivitab tööriistavihje
function InfoButton({ info }) {
const [targetRef, setTargetRef] = React.useState(null);
const [showTooltip, setShowTooltip] = React.useState(false);
return (
setShowTooltip(true)}
onMouseLeave={() => setShowTooltip(false)}
style={{ position: 'relative', display: 'inline-block' }}
>
? {/* Infoikoon */}
{showTooltip && {info} }
);
}
3. Rippmenüüd ja valikukastid
Kohandatud rippmenüüd ja valikukastid saavad samuti portaalidest kasu. Kui rippmenüü avatakse, peab see sageli ulatuma oma vanemkonteineri piiridest kaugemale, eriti kui sellel konteineril on omadused nagu overflow: hidden.
Näidisstsenaarium: Rahvusvahelise ettevõtte sisedashboardil on kohandatud rippmenüü pika nimekirja seast projekti valimiseks. Rippmenüü loend ei tohiks olla piiratud selle dashboardi vidina laiuse ega kõrgusega, milles see asub.
Rakendamise idee: Renderdage rippmenüü valikud portaali, mis on lisatud body'le või spetsiaalsele portaali juurele.
4. Teavitussüsteemid
Globaalsed teavitussüsteemid (toast-sõnumid, hoiatused) on veel üks suurepärane kandidaat createPortal'i jaoks. Need sõnumid ilmuvad tavaliselt fikseeritud asendis, sageli vaateakna üla- või alaosas, sõltumata praegusest kerimisasendist või vanemkomponendi paigutusest.
Näidisstsenaarium: Reisibroneerimissait kuvab kinnitussõnumeid edukate broneeringute kohta või veateateid ebaõnnestunud maksete kohta. Need teated peaksid ilmuma kasutaja ekraanil järjepidevalt.
Rakendamise idee: Spetsiaalset teavituskonteinerit (nt <div id="notifications-root"></div>) saab kasutada koos createPortal'iga.
Kuidas `createPortal`'it Reactis rakendada
createPortal'i rakendamine hõlmab mõnda peamist sammu:
Samm 1: Tuvastage või looge siht-DOM-i sõlm
Teil on vaja DOM-elementi väljaspool standardset Reacti juurt, mis toimiks teie portaali sisu konteinerina. Kõige tavalisem praktika on see määratleda oma peamises HTML-failis (nt public/index.html).
<!-- public/index.html -->
<body>
<noscript>You need JavaScript enabled to run this app.</noscript>
<div id="root"></div>
<div id="modal-root"></div> <!-- Modaalide jaoks -->
<div id="tooltip-root"></div> <!-- Valikuliselt tööriistavihjete jaoks -->
</body>
Alternatiivina saate dünaamiliselt luua DOM-elemendi oma rakenduse elutsükli jooksul JavaScripti abil, nagu on näidatud ülaltoodud modaali näites, ja seejärel lisada see DOM-i. Siiski on HTML-is eelnevalt määratlemine püsivate portaalijuurte jaoks üldiselt puhtam.
Samm 2: Hankige viide siht-DOM-i sõlmele
Oma Reacti komponendis peate sellele DOM-i sõlmele juurde pääsema. Saate seda teha kasutades document.getElementById() või document.querySelector().
// Kusagil teie komponendis või abifailis
const modalRootElement = document.getElementById('modal-root');
const tooltipRootElement = document.getElementById('tooltip-root');
// On oluline tagada, et need elemendid eksisteeriksid enne nende kasutamist.
// Võiksite lisada kontrolle või käsitleda juhtumeid, kus neid ei leita.
Samm 3: Kasutage `ReactDOM.createPortal`
Importige ReactDOM ja kasutage createPortal funktsiooni, edastades oma komponendi JSX-i esimese argumendina ja siht-DOM-i sõlme teisena.
Näide: Lihtsa sõnumi renderdamine portaalis
// MessagePortal.js
import React from 'react';
import ReactDOM from 'react-dom';
function MessagePortal({ message }) {
const portalContainer = document.getElementById('modal-root'); // Eeldades, et kasutate selle näite jaoks modal-root'i
if (!portalContainer) {
console.error('Portaali konteinerit "modal-root" ei leitud!');
return null;
}
return ReactDOM.createPortal(
<div style={{ position: 'fixed', bottom: '20px', left: '50%', transform: 'translateX(-50%)', backgroundColor: 'rgba(0,0,0,0.7)', color: 'white', padding: '10px', borderRadius: '5px' }}>
{message}
</div>,
portalContainer
);
}
export default MessagePortal;
// Teises komponendis...
function Dashboard() {
return (
<div>
<h1>Dashboard Overview</h1>
<MessagePortal message="Data successfully synced!" />
</div>
);
}
Olekute ja sündmuste haldamine portaalidega
Üks createPortal'i olulisemaid eeliseid on see, et see ei riku Reacti sündmuste käsitlemise süsteemi. Portaalides renderdatud elementide sündmused levivad endiselt üles läbi Reacti komponendipuu, mitte ainult DOM-i puu.
Näidisstsenaarium: Modaalaken võib sisaldada vormi. Kui kasutaja klõpsab modaali sees olevat nuppu, peaks klõpsamissündmust käsitlema sündmusekuulaja vanemkomponendis, mis kontrollib modaali nähtavust, mitte olema lõksus modaali enda DOM-hierarhias.
Illustreeriv näide:
// ModalWithEventHandling.js
import React from 'react';
import ReactDOM from 'react-dom';
const modalRoot = document.getElementById('modal-root');
function ModalWithEventHandling({ children, onClose }) {
const modalContentRef = React.useRef(null);
// Kasutame useEffecti DOM-elemendi loomiseks ja puhastamiseks
const [wrapperElement] = React.useState(() => document.createElement('div'));
React.useEffect(() => {
modalRoot.appendChild(wrapperElement);
return () => {
modalRoot.removeChild(wrapperElement);
};
}, [wrapperElement]);
// Käsitleme klikke väljaspool modaali sisu, et see sulgeda
const handleOutsideClick = (event) => {
if (modalContentRef.current && !modalContentRef.current.contains(event.target)) {
onClose();
}
};
return ReactDOM.createPortal(
{children}
,
wrapperElement
);
}
// App.js (kasutades modaali)
function App() {
const [showModal, setShowModal] = React.useState(false);
return (
App Content
{showModal && (
setShowModal(false)}>
Important Information
This is content inside the modal.
)}
);
}
Selles näites kutsub Close Modal nupule klõpsamine korrektselt välja onClose omaduse, mis on edastatud vanemkomponendist App. Samamoodi, kui teil oleks sündmusekuulaja klõpsudele modal-backdrop'il, käivitaks see korrektselt handleOutsideClick funktsiooni, kuigi modaal on renderdatud eraldi DOM-i alampuusse.
Edasijõudnud mustrid ja kaalutlused
Dünaamilised portaalid
Saate luua ja eemaldada portaalide konteinereid dünaamiliselt vastavalt oma rakenduse vajadustele, kuigi püsivate, eelnevalt määratletud portaalijuurte säilitamine on sageli lihtsam.
Portaalid ja serveripoolne renderdamine (SSR)
Serveripoolse renderdamisega (SSR) töötades peate olema teadlik, kuidas portaalid suhtlevad esialgse HTML-iga. Kuna portaalid renderdatakse DOM-i sõlmedesse, mis ei pruugi serveris eksisteerida, peate sageli tingimuslikult renderdama portaali sisu või tagama, et siht-DOM-i sõlmed on SSR-i väljundis olemas.
Levinud muster on kasutada hook'i nagu useIsomorphicLayoutEffect (või kohandatud hook'i, mis eelistab useLayoutEffect'i kliendis ja langeb tagasi useEffect'ile serveris), et tagada DOM-i manipuleerimine ainult kliendi poolel.
// usePortal.js (tavaline abihook'i muster)
import React, { useRef, useEffect } from 'react';
function usePortal(id) {
const modalRootRef = useRef(null);
useEffect(() => {
let currentModalRoot = document.getElementById(id);
if (!currentModalRoot) {
currentModalRoot = document.createElement('div');
currentModalRoot.setAttribute('id', id);
document.body.appendChild(currentModalRoot);
}
modalRootRef.current = currentModalRoot;
// Puhastusfunktsioon loodud elemendi eemaldamiseks, kui see loodi selle hook'i poolt
return () => {
// Ole puhastamisega ettevaatlik; eemalda ainult siis, kui see siin tõesti loodi
// Tugevam lähenemine võiks hõlmata elemendi loomise jälgimist.
};
}, [id]);
return modalRootRef.current;
}
export default usePortal;
// Modal.js (kasutades hook'i)
import React from 'react';
import ReactDOM from 'react-dom';
import usePortal from './usePortal';
function Modal({ children, onClose }) {
const portalTarget = usePortal('modal-root'); // Kasutame oma hook'i
if (!portalTarget) return null;
return ReactDOM.createPortal(
e.stopPropagation()}> {/* Väldime sulgemist seestpoolt klõpsates */}
{children}
,
portalTarget
);
}
SSR-i puhul tagaksite tavaliselt, et modal-root div eksisteerib teie serveris renderdatud HTML-is. Seejärel haagiks Reacti rakendus kliendi poolel end selle külge.
Portaalide stiilimine
Portaali sees olevate elementide stiilimine nõuab hoolikat kaalumist. Kuna need on sageli väljaspool otsese vanema stiilikonteksti, saate portaali sisu välimuse tõhusaks haldamiseks rakendada globaalseid stiile või kasutada CSS-mooduleid/styled-components.
Kihtide, nagu modaalaknad, jaoks vajate sageli stiile, mis:
- Fikseerivad elemendi vaateakna külge (
position: fixed). - Katavad kogu vaateakna (
top: 0; left: 0; width: 100%; height: 100%;). - Kasutavad kõrget
z-indexväärtust, et tagada selle ilmumine kõige muu peal. - Sisaldavad poolläbipaistvat tausta tagaplaanile.
Juurdepääsetavus
Modaalakende või muude kihtide rakendamisel on juurdepääsetavus ülioluline. Veenduge, et haldate fookust õigesti:
- Kui modaalaken avaneb, püüdke fookus modaali sisse. Kasutajad ei tohiks saada sellest väljapoole tabuleerida.
- Kui modaalaken sulgub, tagastage fookus elemendile, mis selle käivitas.
- Kasutage ARIA atribuute (nt
role="dialog",aria-modal="true",aria-labelledby,aria-describedby), et teavitada abitehnoloogiaid modaali olemusest.
Teegid nagu Reach UI või Material-UI pakuvad sageli juurdepääsetavaid modaalkomponente, mis tegelevad nende muredega teie eest.
Võimalikud lõksud ja kuidas neid vältida
Siht-DOM-i sõlme unustamine
Kõige levinum viga on unustada luua siht-DOM-i sõlm oma HTML-is või mitte viidata sellele korrektselt oma JavaScriptis. Veenduge alati, et teie portaali konteiner eksisteerib enne sinna renderdamise katsetamist.
Sündmuste "bubbling" vs. DOM-i "bubbling"
Kuigi Reacti sündmused levivad (bubble up) portaalide kaudu korrektselt, ei tee seda natiivsed DOM-i sündmused. Kui lisate natiivseid DOM-i sündmusekuulajaid otse portaali sees olevatele elementidele, levivad need ainult üles DOM-i puus, mitte Reacti komponendipuus. Püsige võimaluse korral Reacti sünteetilise sündmuste süsteemi juures.
Kattuvad portaalid
Kui teil on mitut tüüpi kihte (modaalaknad, tööriistavihjed, teated), mis kõik renderdatakse body'sse või ühisesse juure, võib nende virnastamisjärjekorra haldamine muutuda keeruliseks. Spetsiifiliste z-index väärtuste määramine või portaalide haldamise süsteemi kasutamine võib aidata.
Jõudlusega seotud kaalutlused
Kuigi createPortal ise on tõhus, võib keerukate komponentide renderdamine portaalides siiski jõudlust mõjutada. Veenduge, et teie portaali sisu on optimeeritud, ja vältige tarbetuid uuesti renderdamisi.
Alternatiivid `createPortal`'ile
Kuigi createPortal on Reacti idioomne viis nende stsenaariumide käsitlemiseks, on väärt märkida ka teisi lähenemisviise, millega võite kokku puutuda või mida kaaluda:
- Otsene DOM-i manipuleerimine: Võiksite käsitsi luua ja lisada DOM-elemente kasutades
document.createElementjaappendChild, kuid see möödub Reacti deklaratiivsest renderdamisest ja olekuhaldusest, muutes selle vähem hooldatavaks. - Higher-Order Components (HOCs) või Render Props: Need mustrid võivad abstraheerida portaalide renderdamise loogikat, kuid
createPortalise on selle aluseks olev mehhanism. - Komponentide teegid: Paljud kasutajaliidese komponentide teegid (nt Material-UI, Ant Design, Chakra UI) pakuvad eelnevalt ehitatud modaal-, tööriistavihje- ja rippmenüü komponente, mis abstraheerivad
createPortal'i kasutamise, pakkudes mugavamat arendajakogemust. Siiski oncreatePortal'i mõistmine ülioluline nende komponentide kohandamiseks või omaenda loomiseks.
Kokkuvõte
React.createPortal on võimas ja oluline funktsioon keerukate kasutajaliideste loomiseks Reactis. Võimaldades teil renderdada komponente DOM-i sõlmedesse väljaspool nende Reacti puu hierarhiat, lahendab see tõhusalt levinud probleeme, mis on seotud CSS-i z-index'i, virnastamiskontekstide ja elementide ülevooluga.
Olenemata sellest, kas loote keerukaid modaaldialooge kasutaja kinnituseks, peeneid tööriistavihjeid kontekstuaalse teabe jaoks või globaalselt nähtavaid teavitusribasid, pakub createPortal vajalikku paindlikkust ja kontrolli. Ärge unustage hallata oma portaali DOM-i sõlmi, käsitleda sündmusi korrektselt ning seada esikohale juurdepääsetavus ja jõudlus, et luua tõeliselt vastupidav ja kasutajasõbralik rakendus, mis sobib globaalsele publikule, kellel on erinevad tehnilised taustad ja vajadused.
createPortal'i valdamine tõstab kahtlemata teie Reacti arendusoskusi, võimaldades teil luua lihvitumaid ja professionaalsemaid kasutajaliideseid, mis paistavad silma kaasaegsete veebirakenduste üha keerukamaks muutuval maastikul.