Angenommen, wir müssen ein Kindelement in einer React-Anwendung rendern. Einfach, oder? Dieses Kind wird an das nächstgelegene DOM-Element angehängt und dementsprechend darin gerendert.
render() {
return (
<div>
// Child to render inside of the div
</div>
);
}
Aber! Was, wenn wir dieses Kind *außerhalb* des Divs woanders rendern wollen? Das kann knifflig sein, da es die Konvention bricht, dass eine Komponente als neues Element gerendert werden und einer Eltern-Kind-Hierarchie folgen muss. Der Elternteil möchte dorthin gehen, wo sein Kind hingeht.
Hier kommen React Portals ins Spiel. Sie bieten eine Möglichkeit, Elemente außerhalb der DOM-Hierarchie zu rendern, damit Elemente etwas portabler sind. Es ist vielleicht keine perfekte Analogie, aber Portale sind so etwas wie die Rohre in Mario Bros., die dich aus dem normalen Spielfluss transportieren und in eine andere Region bringen.

Das Coole an Portalen? Auch wenn sie ihre eigenen Ereignisse auslösen, die unabhängig vom Elternelement des Kindes sind, hört der Elternteil immer noch auf diese Ereignisse, was nützlich sein kann, um Ereignisse in einer App weiterzugeben.
Wir werden in diesem Beitrag gemeinsam ein Portal erstellen und es dann zu einer wiederverwendbaren Komponente machen. Los geht's!
Das Beispiel, das wir erstellen
Hier ist ein relativ einfaches Beispiel für ein Portal in Aktion
Siehe den Pen React Portal von Kingsley Silas Chijioke (@kinsomicrote) auf CodePen.
Das Umschalten der Sichtbarkeit eines Elements ist nichts Neues. Wenn Sie sich jedoch den Code genau ansehen, werden Sie feststellen, dass das ausgegebene Element vom Button gesteuert wird, obwohl es kein direkter Nachkomme davon ist. Tatsächlich, wenn Sie den Quellcode mit der gerenderten Ausgabe in DevTools vergleichen, sehen Sie die Beziehung

Das Elternelement des ausgegebenen Elements hört also tatsächlich auf das Klicken des Buttons und erlaubt, dass das Kind eingefügt wird, obwohl es und der Button separate Geschwister im DOM sind. Lassen Sie uns die Schritte zur Erstellung dieses umzuschaltbaren Portal-Elements aufschlüsseln, um zu sehen, wie alles funktioniert.
Schritt 1: Das Portal-Element erstellen
Die erste Zeile einer React-Anwendung gibt an, dass ein App-Element im Dokument-Root mit ReactDOM gerendert wird. So:
ReactDOM.render(<App />, document.getElementById("root"));
Wir müssen das App-Element in einer HTML-Datei platzieren, um es auszuführen
<div id="App"></div>
Ähnlich wie bei Portalen. Als erstes erstellen wir zum Erstellen eines Portals ein neues Div-Element in der HTML-Datei.
<div id="portal"></div>
Dieses Div dient als unser Ziel. Wir verwenden `#portal` als ID, aber das muss nicht so sein. Jede Komponente, die innerhalb dieses Ziel-Divs gerendert wird, behält den Kontext von React. Wir müssen das Div als Wert einer Variablen speichern, damit wir die Portal-Komponente, die wir erstellen werden, nutzen können
const portalRoot = document.getElementById("portal");
Sieht dem Aufruf des App-Elements sehr ähnlich, richtig?
Schritt 2: Eine Portal-Komponente erstellen
Als Nächstes richten wir das Portal als Komponente ein
class Portal extends React.Component {
constructor() {
super();
// 1: Create a new div that wraps the component
this.el = document.createElement("div");
}
// 2: Append the element to the DOM when it mounts
componentDidMount = () => {
portalRoot.appendChild(this.el);
};
// 3: Remove the element when it unmounts
componentWillUnmount = () => {
portalRoot.removeChild(this.el);
};
render() {
// 4: Render the element's children in a Portal
const { children } = this.props;
return ReactDOM.createPortal(children, this.el);
}
}
Lassen Sie uns einen Schritt zurücktreten und betrachten, was hier passiert.
Wir erstellen im Konstruktor ein neues Div-Element und setzen es als Wert für `this.el`. Wenn die Portal-Komponente gemountet wird, wird `this.el` als Kind zu diesem Div in der HTML-Datei hinzugefügt, wo wir es hinzugefügt haben. Das ist in unserem Fall die Zeile `<div id="portal"></div>`.
Der DOM-Baum wird so aussehen.
<div> // Portal, which is also portalRoot
<div> // this.el
</div>
</div>
Wenn Sie neu in React sind und mit dem Konzept des Mountens und Unmountens eines Elements verwirrt sind, hat Jake Trent eine gute Erklärung. TL;DR: Mounten ist der Moment, in dem das Element in den DOM eingefügt wird.
Wenn die Komponente unmounted wird, wollen wir das Kind entfernen, um Speicherlecks zu vermeiden. Wir werden diese Portal-Komponente in eine andere Komponente importieren, wo sie verwendet wird, nämlich in das Div, das in unserem Beispiel den Header und den Button enthält. Dabei werden wir die Kind-Elemente der Portal-Komponente mitnehmen. Deshalb haben wir `this.props.children`.
Schritt 3: Das Portal verwenden
Um die Kind-Elemente der Portal-Komponente zu rendern, verwenden wir `ReactDOM.createPortal()`. Dies ist eine spezielle ReactDOM-Methode, die die Kinder und das erstellte Element akzeptiert. Um zu sehen, wie das Portal funktioniert, verwenden wir es in unserer App-Komponente.
Bevor wir das tun, behandeln wir die Grundlagen, wie die App funktionieren soll. Wenn die App geladen wird, wollen wir einen Text und einen Button anzeigen – wir können dann den Button umschalten, um die Portal-Komponente ein- oder auszublenden.
class App extends React.Component {
// The initial toggle state is false so the Portal element is out of view
state = {
on: false
};
toggle = () => {
// Create a new "on" state to mount the Portal component via the button
this.setState({
on: !this.state.on
});
};
// Now, let's render the components
render() {
const { on } = this.state;
return (
// The div where that uses the Portal component child
<div>
<header>
<h1>Welcome to React</h1>
</header>
<React.Fragment>
// The button that toggles the Portal component state
// The Portal parent is listening for the event
<button onClick={this.toggle}>Toggle Portal</button>
// Mount or unmount the Portal on button click
<Portal>
{
on ?
<h1>This is a portal!</h1>
: null
}
</Portal>
</React.Fragment>
</div>
);
}
}
Da wir das Portal ein- und ausschalten wollen, müssen wir den Komponentenstatus verwenden, um das Umschalten zu verwalten. Dies ist im Grunde eine Methode, um den Status `on` bei einem Klickereignis entweder auf `true` oder `false` zu setzen. Das Portal wird gerendert, wenn `on` true ist; andernfalls rendern wir nichts.
So sieht der DOM aus, wenn der `on`-Status auf `true` gesetzt ist.

Wenn `on` `false` ist, wird die Portal-Komponente nicht im Root gerendert, daher sieht der DOM so aus.

Weitere Anwendungsfälle
Modals sind ein perfekter Kandidat für Portale. Tatsächlich verwenden die React-Dokumente sie als Hauptbeispiel für die Funktionsweise von Portalen
Siehe den Pen Example: Portals von Dan Abramov (@gaearon) auf CodePen.
Es ist das gleiche Konzept, bei dem eine Portal-Komponente erstellt wird und ein Zustand verwendet wird, um die Kind-Elemente an die Modal-Komponente anzuhängen.
Wir können sogar Daten von einer externen Quelle in ein Modal einfügen. In diesem Beispiel listet die App-Komponente Benutzer auf, die von einer API mithilfe von axios abgerufen wurden.
Siehe den Pen React Portal 3 von Kingsley Silas Chijioke (@kinsomicrote) auf CodePen.
Wie wäre es mit Tooltips? David Gilberston hat eine schöne Demo
Siehe den Pen React Portal Tooptip von David Gilbertson (@davidgilbertson) auf CodePen.
J Scott Smith zeigt, wie Portale zum Entkommen von Positionierungen verwendet werden können
Er hat ein weiteres schickes Beispiel, das das Einfügen von Elementen *und* die Verwaltung von Zuständen demonstriert
Zusammenfassung
Das war's! Hoffentlich gibt Ihnen dies ein solides Grundverständnis von Portalen, was sie sind, was sie tun und wie man sie in einer React-Anwendung verwendet. Das Konzept mag trivial erscheinen, aber die Fähigkeit, Elemente außerhalb der DOM-Hierarchie zu verschieben, ist eine praktische Möglichkeit, Komponenten etwas erweiterbarer und wiederverwendbarer zu machen ... all das weist auf die Kernvorteile der Verwendung von React an erster Stelle hin.
Weitere Informationen
- React Portals Dokumentation
- React v16 Release Notes – Die Veröffentlichung, in der Portale eingeführt wurden
- CodePen Beispiele – Eine Suche nach React Portals
Lol, dieses Portal ist ein Portal in die Hölle. Sobald Sie eine große Codebasis haben, ist diese Art von Ansatz nicht gut.
Wie unterscheiden sich Portale von Fragmenten?
Hallo Jen, Fragmente und Portale sind völlig unterschiedlich. Ich hoffe, ich kann es gut erklären. Fragmente werden verwendet, wenn wir effektiv zwei Elemente zurückgeben möchten, aber ohne sie in ein beliebiges Element einwickeln zu müssen. Nehmen wir zum Beispiel an, wir wollten eine Komponente, die einen Absatz und einen Button zurückgibt, das ist nicht erlaubt, weil wir zwei Elemente zurückgeben
Wir könnten sie in ein Div oder etwas einwickeln, damit eine Sache zurückgegeben wird, aber aus bestimmten Gründen, die wir vielleicht haben, möchten wir dieses Div vielleicht nicht nur, weil wir gezwungen waren, eine Sache zurückzugeben. Das `<Fragment>` kann als Wrapper verwendet werden, damit JSX eine Sache zurückgegeben sieht, aber Fragmente rendern kein DOM, sodass es uns effektiv die Möglichkeit gibt, zwei DOM-Knoten ohne Wrapper zurückzugeben.
Portale sind eher eine Fähigkeit, einer Komponente zu ermöglichen zu entscheiden, wo im DOM sie ihre Ausgabe rendern wird. Wenn ich zum Beispiel Lightboxen (Modals) habe, mag ich es nicht, wenn das eigentliche DOM der Lightbox direkt neben dem Button liegt, der die Lightbox geöffnet hat. Ich habe dafür bestimmte (CSS-)Gründe. Da meine App nur eine Lightbox gleichzeitig zulässt und da ich meine CSS-Gründe habe, um ihr DOM weiter oben in der Kette zu platzieren, verwende ich Portale, um die Lightbox als Geschwister des `<div id="root">` zu "rendern".
Ich würde diesen Ansatz nicht für größere Anwendungen empfehlen.