React.js-Portal

Die Magie des Renderns von Elementen außerhalb des eigenen DOM-Baums

Teleportation in React.js

Wussten Sie, dass React eine spezielle und sehr leistungsstarke Komponente namens „Portal“ bereitstellt, die ihre Kinder an einer ganz anderen Stelle in Ihrer App einbinden kann? Wenn nicht, ist es Zeit, etwas Neues zu lernen!

Die Anatomie eines React.js-Portals

Hier ist ein kurzer Überblick darüber, wie die Portal-Komponente in React.js zuvor funktioniert.

  • Irgendwo in Ihrem Code mounten Sie ein Element, das die Kinder des Portals hosten wird
  • Dann erhalten Sie einen Verweis auf dieses Element
  • An einer anderen Stelle in Ihrer App mounten Sie dann die Portal-Komponente und übergeben die vom Host-Element erhaltene Referenz
  • Alles, was jetzt im Portal gemountet ist, wird vom ersten Schritt an tatsächlich im Host gemountet

Um besser zu verstehen, was vor sich geht, habe ich die folgenden einfachen Visualisierungen erstellt, um die Portal-Funktionalität zu veranschaulichen.

Image ee9c2dac28e7

Image 70ff8978589d

Image 886ed0a34985

Aufbauend auf diesen Bildern zeigen die folgenden Grafiken den gleichen Prozess, diesmal jedoch mit vereinfachten Codebeispielen.

Image dd655b015a22

Image ab94e9940e3a

Das Portal ist noch mächtiger, als Sie zunächst denken. Es ermöglicht sogar, mehrere Kinder aus mehreren Portalen in dasselbe Zielelement zu rendern. Die Montagereihenfolge der Portale definiert auch die Reihenfolge der Elemente im Host.

Image de39ae9a02a2

Image b12fdf680f24

Das Teilen des Verweises auf das Host-Element, das alle teleportierten Kinder enthält, ist ebenfalls sehr einfach. Die offizielle Dokumentation beschreibt die Verwendung von document.getElementById, aber Sie können auch den useRef-Hook von React.js verwenden. Das folgende Codebeispiel zeigt eine einfache Implementierung, die alles zeigt, was bisher beschrieben wurde.

import React, { useEffect, useRef, useState } from "react";
import ReactDOM, { createPortal } from "react-dom";

//
// Link to sandbox:
// 👉 https://codesandbox.io/s/react-16-8-0-forked-d8lm1?file=/src/index.js:0-1067
//

// A simple demonstration of the React-Portal
// w/ multiple portals for the same target.
function App() {
  const ref = useRef(null);
  const [isRefReady, setIsRefReady] = useState(false);

  // Run one more render to actually
  // show the content of our portal.
  // This is necessary, as the setter
  // for the 'ref' alone won't trigger
  // a render.
  useEffect(() => {
    setIsRefReady(Boolean(ref));
  }, []);

  return (
    <div>
      <div>
        {/* The 'target' aka host for our portals. */}
        <header ref={ref} style={{display: "flex", gap: 8 }} />
        <hr/>
      </div>
      <h1>
        Debug
      </h1>
      {isRefReady && createPortal(<button>one</button>, ref.current)}
      {isRefReady && createPortal(<button>two</button>, ref.current)}
      <div>
        {isRefReady && createPortal(<button>three</button>, ref.current)}
      </div>
    </div>
  );
}

ReactDOM.render(<App />, document.querySelector("#root"));

Wie die Portal-Komponente eine einfachere Codierung ermöglicht

Der wahrscheinlich häufigste Anwendungsfall für das React.js-Portal ist die Implementierung einer Modal-Komponente. Definieren Sie einfach das Ziel an der Wurzel Ihres App-Baums und verwenden Sie die Portal-Komponente, um ein Modal von überall her zu mounten, das zuverlässig über allen Inhalten schwebt.

Ein weiterer Anwendungsfall, den ich tatsächlich implementiert habe, ist die Verwendung eines Tab-Containers. Da ein Tab-Container sowohl ein Tab-Element selbst als auch den Inhalt zum Rendern benötigt, wenn der Tab ausgewählt wird, definiere ich einfach zwei Hosts, einen für die Tab-Zeile und den anderen für den ausgewählten Inhalt.

Dann mounte ich einfach ein Array von Komponenten, die jeweils ein Portal für das Tab-Element sowie ausgewählte Inhalte verwenden. Dadurch kann ich die Geschäftslogik dort platzieren, wo sie eigentlich hingehört – in jede einzelne Komponente.

Image 2761da74cf8c

Image e7810bb469d2

Es gibt sicherlich noch weitere interessante Anwendungsfälle für die Portal-Komponente. Der größte Vorteil, den es meiner Meinung nach ermöglicht, ist die enge Kopplung der Geschäftslogik in einer einzigen Komponente, deren Kinder dann an verschiedenen Stellen montiert werden. Dieses Muster ermöglicht eine große Flexibilität und Anpassung, kann jedoch zu Verwirrung in Ihrer Codebasis führen, wie die Ansichten tatsächlich zusammenhängen.

Bitte werfen Sie auch einen Blick in die offizielle Dokumentation für alle Details zu React.js-Portalen.