W React, umiejscowienie komponentu w strukturze DOM zazwyczaj zależy od miejsca jego wywołania w kodzie. Z reguły komponent jest umieszczany dokładnie tam, gdzie go zdefiniowaliśmy. Jednak czasami pojawia się potrzeba, aby komponent wyrenderował swój kod JSX w innym miejscu niż to, w którym został wywołany. Przykładem może być sytuacja, gdy chcemy wyświetlić błędy formularza w specyficznym miejscu strony. W takich przypadkach nadal chcemy zachować deklaratywny charakter Reacta, czyli zamiast bezpośrednio manipulować DOM-em, po prostu informujemy Reacta, gdzie chcemy, aby nasz komponent został wyrenderowany.

Jak używać portali?

Aby wykorzystać portale, dodajemy w pliku index.html element DOM, do którego chcemy przenieść wyrenderowaną zawartość. Przykładowo, możemy zmodyfikować standardowy plik index.html wygenerowany przez create-react-app, dodając element o id modal-root:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
     ....
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <div id="modal-root"></div> <!-- Tutaj dodaliśmy nowy element -->
  </body>
</html>

Następnie, w naszej aplikacji React, używamy createPortal w pliku Modal.js, aby wyrenderować zawartość modalu w elemencie modal-root.

plik App.js

import React, { useState } from 'react';
import Modal from './Modal';

function App() {
  const [isModalOpen, setModalOpen] = useState(false);

  return (
    <div>
      <h1>Kliknij poniżej, aby otworzyć modal:</h1>
      <button onClick={() => setModalOpen(true)}>Otwórz Modal</button>
      {isModalOpen && (
        <Modal onClose={() => setModalOpen(false)}>
          <p>To jest treść modalu!</p>
          <button onClick={() => setModalOpen(false)}>Zamknij Modal</button>
        </Modal>
      )}
    </div>
  );
}

export default App;

Oraz nasz plik Modal.js, w którym zastosowałem createPortal

import React from 'react';
import { createPortal } from 'react-dom';

const Modal = ({ onClose, children }) => {
  return createPortal(
    <div style={{position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', backgroundColor: 'white', padding: '20px', zIndex: 1000}}>
      {children}
      <button onClick={onClose}>Zamknij</button>
    </div>,
    document.getElementById('modal-root')
  );
}

export default Modal;

W tym przykładzie, zawartość modalu jest renderowana przy użyciu createPortal w elemencie DOM o id modal-root. Dzięki temu modal może „wyskoczyć” poza zwykłą hierarchię renderowania komponentów React, co pozwala na umieszczenie go w dowolnym miejscu strony. Jest to szczególnie przydatne dla komponentów takich jak modale, które wizualnie chcemy oddzielić od reszty aplikacji.

Kiedy używać Portali?

Portale znajdują swoje zastosowanie w kilku typowych przypadkach:

  • Modale, lightboxy, tooltipy: Gdy chcemy, aby elementy te były renderowane w korzeniu dokumentu, aby uniknąć problemów z CSS (np. z overflow lub z-index).
  • Dostępność (a11y): Przenosząc modale do korzenia DOM, możemy łatwiej zarządzać fokusem i nie przerywać sekwencji czytania ekranu dla użytkowników korzystających z czytników ekranu.
  • Unikanie konfliktów z CSS: Kiedy komponenty muszą być „wyrwane” z obecnego kontekstu, aby uniknąć problemów z dziedziczeniem stylów lub niewłaściwym pozycjonowaniem.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *