createPortal

createPortal bazı alt elemanları DOM’un farklı bir bölümünde render etmenize olanak tanır.

<div>
<SomeComponent />
{createPortal(children, domNode, key?)}
</div>

Başvuru dokümanı

createPortal(children, domNode, key?)

Bir portal oluşturmak için, biraz JSX ve render edilmesi gereken DOM düğümünü ileterek createPortal’ı çağırın:

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>

Aşağıda daha fazla örnek görebilirsiniz.

Bir portal yalnızca DOM düğümünün fiziksel yerleşimini değiştirir. Diğer her şekilde, bir portala render ettiğiniz JSX, onu render eden React bileşeninin alt düğümü gibi davranır. Örneğin, alt eleman üst ağaç tarafından sağlanan context’e erişebilir ve olaylar React ağacına göre alt elemanlardan üst elemanlara doğru ilerler.

Parametreler

  • children: Bir JSX parçası gibi React ile render edilebilen herhangi bir şey (örneğin <div /> ya da <HerhangiBileşen />), bir Fragment (<>...</>), bir string ya da bir sayı, veya bunlardan oluşan bir dizi.

  • domNode: document.getElementById() tarafından döndürülen bir DOM düğümü. Düğüm halihazırda mevcut olmalıdır. Güncelleme sırasında farklı bir DOM düğümünün parametre olarak geçilmesi portal içeriğinin yeniden oluşturulmasına neden olacaktır.

  • opsiyonel key: Portalın anahtarı olarak kullanılacak benzersiz bir string veya sayı.

Dönüş değeri

createPortal JSX’e dahil edilebilen veya bir React bileşeninden döndürülebilen bir React düğümü döndürür. React render çıktısında bununla karşılaşırsa, sağlanan children’ı sağlanan domNode’un içine yerleştirecektir.

Uyarılar

  • Portallardan gelen olaylar DOM ağacı yerine React ağacına göre yayılır. Örneğin, bir portalın içine tıklarsanız ve portal <div onClick> içine sarılırsa, bu onClick yöneticisi tetiklenecektir. Bu sorunlara neden oluyorsa, ya portalın içinden olay yayılımını durdurunuz ya da portalın kendisini React ağacında yukarı taşıyınız.

Kullanım

DOM’un farklı bir bölümüne render etme

Portallar bileşenlerinizin bazı alt elemanlarını DOM’da farklı bir yerde render etmenize izin verir. Bu, bileşeninizin bir parçasının içinde bulunduğu konteynerlerden “kaçmasını” sağlar. Örneğin, bir bileşen, sayfanın geri kalanının üstünde ve dışında görünen bir modal iletişim kutusu veya bir araç ipucu görüntüleyebilir.

Bir portal oluşturmak için, createPortal sonucunu biraz JSX ve gitmesi gereken DOM düğümü ile render ediniz:

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, sağladığınız JSX için DOM düğümlerini sağladığınız DOM düğümünün içine yerleştirecektir.

Portal olmasaydı, ikinci <p> ana <div> içine yerleştirilirdi, ancak portal onu document.body içine “ışınladı”:

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

İkinci paragrafın kenarla birlikte görsel olarak ana <div>’in dışında nasıl göründüğüne dikkat edin. DOM yapısını geliştirici araçlarıyla incelerseniz, ikinci <p>’nin doğrudan <body> içine yerleştirildiğini görebilirsiniz:

<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>

Bir portal, DOM düğümünün yalnızca fiziksel yerleşimini değiştirir. Diğer her şekilde, bir portala render ettiğiniz JSX, onu render eden React bileşeninin alt düğümü gibi davranır. Örneğin, alt eleman ana ağaç tarafından sağlanan bağlama erişebilir ve olaylar React ağacına göre alt elemanlardan üst elemanlara doğru ilerlemeye devam eder.


Portal ile modal iletişim kutusu render etme

Diyaloğu çağıran bileşen overflow: hidden veya diyaloğa müdahale eden diğer stillere sahip bir kapsayıcı içinde olsa bile, sayfanın geri kalanının üzerinde bulunan bir modal diyalog penceresi oluşturmak için bir portal kullanabilirsiniz.

Bu örnekte, iki kapsayıcı da modal iletişim kutusunu bozan stillere sahiptir, ancak DOM’da modal üst JSX öğeleri içinde yer almadığı için portalda render edilen stil etkilenmez.

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

Tuzak

Portalları kullanırken uygulamanızın erişilebilir olduğundan emin olmanız önemlidir. Örneğin, kullanıcının odağı doğal bir şekilde portalın içine ve dışına taşıyabilmesi için klavye odağını yönetmeniz gerekebilir.

Modal’lar oluştururken WAI-ARIA Modal Yazma Uygulamaları kılavuzunu izleyiniz. Bir topluluk paketi kullanıyorsanız, erişilebilir olduğundan ve bu yönergeleri izlediğinden emin olun.


React bileşenlerini React olmayan sunucu biçimlendirmesine render etme

Portallar, React kökünüz React ile oluşturulmamış statik veya sunucu tarafından render edilen bir sayfanın parçasıysa yararlı olabilir. Örneğin, sayfanız Rails gibi bir sunucu çatısı ile oluşturulmuşsa, sidebar gibi statik alanlar içinde etkileşim alanları oluşturabilirsiniz. Birden fazla ayrı React köküne sahip olmakla karşılaştırıldığında, portallar, parçaları DOM’un farklı bölümlerine render edilse bile uygulamayı paylaşılan state’e sahip tek bir React ağacı olarak ele almanızı sağlar.

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 bileşenlerini React olmayan DOM düğümlerine render etme

React dışında yönetilen bir DOM düğümünün içeriğini yönetmek için de bir portal kullanabilirsiniz. Örneğin, React olmayan bir harita widget’ı ile entegre olduğunuzu ve React içeriğini bir açılır pencere içinde redner etmek istediğinizi varsayalım. Bunu yapmak için, içine render edeceğiniz DOM düğümünü saklamak üzere bir popupContainer state değişkeni tanımlayabilirsiniz:

const [popupContainer, setPopupContainer] = useState(null);

Üçüncü parti widget’ı oluşturduğunuzda, widget tarafından döndürülen DOM düğümünü depo edin, böylece içine render edebilirsiniz:

useEffect(() => {
if (mapRef.current === null) {
const map = createMapWidget(containerRef.current);
mapRef.current = map;
const popupDiv = addPopupToMapWidget(map);
setPopupContainer(popupDiv);
}
}, []);

Bu, React içeriğini kullanılabilir hale geldiğinde popupContainer içine render etmek için createPortal kullanmanızı sağlar:

return (
<div style={{ width: 250, height: 250 }} ref={containerRef}>
{popupContainer !== null && createPortal(
<p>Hello from React!</p>,
popupContainer
)}
</div>
);

İşte kurcalayabileceğiniz eksiksiz bir örnek:

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