createPortal מאפשר לך להפוך חלק מהילדים לחלק אחר של DOM.
<div>
<SomeComponent />
{createPortal(children, domNode, key?)}
</div>הפניה
createPortal(children, domNode, key?)
כדי ליצור פורטל, התקשר ל-createPortal, העברת כמה JSX, ואת הצומת DOM שבו יש להציג אותו:
import { createPortal } from 'react-dom';
// ...
<div>
<p>This child is placed in the parent div.</p>
{createPortal(
<p>This child is placed in the document body.</p>,
document.body
)}
</div>פורטל משנה רק את המיקום הפיזי של הצומת DOM. בכל דרך אחרת, ה-JSX שאתה מעבד לפורטל פועל כצומת צאצא של הרכיב React שמעבד אותו. לדוגמה, הילד יכול לגשת להקשר שמספק עץ האב, ואירועים מבעבעים מהילדים להורים לפי העץ React.
פרמטרים
-
children: כל דבר שניתן לעבד עם React, כמו חתיכה של JSX (למשל<div />או<SomeComponent />), [Fragment] (/reference/react/Fragment) (<>...</>), או מחרוזת או מערך. -
domNode: צומת DOM כלשהו, כגון אלו שהוחזרו על ידיdocument.getElementById(). הצומת חייב כבר להתקיים. העברת צומת DOM אחר במהלך עדכון תגרום לuse את תוכן הפורטל שייווצר מחדש. -
אופציונלי
key: מחרוזת או מספר ייחודיים להיות used בתור מפתח.
מחזירה
createPortal מחזירה צומת React שניתן לכלול ב-JSX או להחזירו מרכיב React. אם React נתקל בו בפלט העיבוד, הוא יציב את ה-children המסופק בתוך ה-domNode המסופק.
אזהרות
- אירועים מפורטלים מתפשטים לפי עץ React ולא עץ DOM. לדוגמה, אם תלחץ בתוך פורטל, והפורטל עטוף ב-
<div onClick>, מטפל ה-onClickהזה יפעל. אם ה-causes בעיות, או עצור את הפצת האירועים מתוך הפורטל, או העבר את הפורטל עצמו למעלה בעץ React.
שימוש
עיבוד לחלק אחר של DOM
פורטלים מאפשרים לרכיבים שלך להפוך חלק מהילדים שלהם למקום אחר ב-DOM. זה מאפשר לחלק מהרכיב שלך “לברוח” מכל מיכל שהוא נמצא בתוכם. לדוגמה, רכיב יכול להציג דו-שיח מודאלי או הסבר כלים המופיע מעל ומחוץ לשאר העמוד.
כדי ליצור פורטל, עבד את התוצאה של createPortal עם כמה JSX והצומת DOM לאן שהוא אמור להגיע:
import { createPortal } from 'react-dom';
function MyComponent() {
return (
<div style={{ border: '2px solid black' }}>
<p>This child is placed in the parent div.</p>
{createPortal(
<p>This child is placed in the document body.</p>,
document.body
)}
</div>
);
}React ישים את הצמתים DOM עבור JSX שהעברת בתוך הצומת DOM שסיפקת.
ללא פורטל, <p> השני יוצב בתוך האב <div>, אבל הפורטל “טלפורט” אותו לתוך document.body:
import { createPortal } from 'react-dom'; export default function MyComponent() { return ( <div style={{ border: '2px solid black' }}> <p>This child is placed in the parent div.</p> {createPortal( <p>This child is placed in the document body.</p>, document.body )} </div> ); }
שימו לב כיצד הפסקה השנייה מופיעה חזותית מחוץ להורה <div> עם הגבול. אם תבדוק את מבנה DOM עם כלי מפתחים, תראה שה-<p> השני הוכנס ישירות ל-<body>:
<body>
<div id="root">
...
<div style="border: 2px solid black">
<p>This child is placed inside the parent div.</p>
</div>
...
</div>
<p>This child is placed in the document body.</p>
</body>פורטל משנה רק את המיקום הפיזי של הצומת DOM. בכל דרך אחרת, ה-JSX שאתה מעבד לפורטל פועל כצומת צאצא של הרכיב React שמעבד אותו. לדוגמה, הילד יכול לגשת להקשר שמספק עץ האב, ואירועים עדיין מבעבעים מהילדים להורים לפי העץ React.
עיבוד דו-שיח מודאלי עם פורטל
אתה יכול use פורטל כדי ליצור דיאלוג מודאלי שצף מעל שאר העמוד, גם אם הרכיב שמזמן את הדיאלוג נמצא בתוך קונטיינר עם overflow: hidden או סגנונות אחרים שמפריעים לדיאלוג.
בדוגמה זו, לשני הקונטיינרים יש סגנונות שמשבשים את הדו-שיח המודאלי, אך זה שעובד לפורטל אינו מושפע מכיוון שuse, ב-DOM, המודאל אינו כלול ברכיבי האב JSX.
import NoPortalExample from './NoPortalExample'; import PortalExample from './PortalExample'; export default function App() { return ( <> <div className="clipping-container"> <NoPortalExample /> </div> <div className="clipping-container"> <PortalExample /> </div> </> ); }
עיבוד רכיבי React לתוך סימון שרת שאינו React
פורטלים יכולים להיות מלאים use אם השורש React שלך הוא רק חלק מדף סטטי או מעובד בשרת שאינו בנוי עם React. לדוגמה, אם הדף שלך בנוי עם מסגרת שרת כמו Rails, אתה יכול ליצור אזורים של אינטראקטיביות בתוך אזורים סטטיים כמו סרגלי צד. בהשוואה לפורטלים של מספר שורשים נפרדים של React, מאפשרים לך להתייחס לאפליקציה כאל עץ React יחיד עם state משותף למרות שהחלקים שלה __T מעבדים __T שונים.
import { createPortal } from 'react-dom'; const sidebarContentEl = document.getElementById('sidebar-content'); export default function App() { return ( <> <MainContent /> {createPortal( <SidebarContent />, sidebarContentEl )} </> ); } function MainContent() { return <p>This part is rendered by React</p>; } function SidebarContent() { return <p>This part is also rendered by React!</p>; }
עיבוד רכיבי React לצמתים שאינם React DOM
אתה יכול גם use פורטל לניהול התוכן של צומת DOM המנוהל מחוץ ל-React. לדוגמה, נניח שאתה משתלב עם ווידג’ט מפה שאינו React וברצונך להציג תוכן React בתוך חלון קופץ. כדי לעשות זאת, הכריז על משתנה popupContainer state כדי לאחסן את הצומת DOM שאליו אתה הולך לרנדר:
const [popupContainer, setPopupContainer] = useState(null);כאשר אתה יוצר את הווידג’ט של צד שלישי, אחסן את הצומת DOM שהוחזר על ידי הווידג’ט כדי שתוכל לעבד אותו:
useEffect(() => {
if (mapRef.current === null) {
const map = createMapWidget(containerRef.current);
mapRef.current = map;
const popupDiv = addPopupToMapWidget(map);
setPopupContainer(popupDiv);
}
}, []);זה מאפשר לך use createPortal לעבד תוכן React ל-popupContainer ברגע שהוא יהיה זמין:
return (
<div style={{ width: 250, height: 250 }} ref={containerRef}>
{popupContainer !== null && createPortal(
<p>Hello from React!</p>,
popupContainer
)}
</div>
);הנה דוגמה מלאה שתוכל לשחק איתה:
import { useRef, useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; import { createMapWidget, addPopupToMapWidget } from './map-widget.js'; export default function Map() { const containerRef = useRef(null); const mapRef = useRef(null); const [popupContainer, setPopupContainer] = useState(null); useEffect(() => { if (mapRef.current === null) { const map = createMapWidget(containerRef.current); mapRef.current = map; const popupDiv = addPopupToMapWidget(map); setPopupContainer(popupDiv); } }, []); return ( <div style={{ width: 250, height: 250 }} ref={containerRef}> {popupContainer !== null && createPortal( <p>Hello from React!</p>, popupContainer )} </div> ); }