Українська

Детальний посібник з порталів React, що охоплює їхні варіанти використання, реалізацію, переваги та найкращі практики для рендерингу вмісту поза стандартною ієрархією компонентів.

Портали React: Рендеринг вмісту поза деревом компонентів

Портали React надають потужний механізм для рендерингу дочірніх компонентів у вузол DOM, що існує поза ієрархією DOM батьківського компонента. Ця техніка є неоціненною в різних сценаріях, таких як модальні вікна, підказки та ситуації, коли вам потрібен точний контроль над позиціонуванням та порядком накладання елементів на сторінці.

Що таке портали React?

У типовому застосунку React компоненти рендеряться в межах суворої ієрархічної структури. Батьківський компонент містить дочірні компоненти, і так далі. Однак іноді потрібно вирватися з цієї структури. Саме тут на допомогу приходять портали React. Портал дозволяє рендерити вміст компонента в іншу частину DOM, навіть якщо ця частина не є прямим нащадком компонента в дереві React.

Уявіть, що у вас є модальний компонент, який повинен відображатися на верхньому рівні вашого застосунку, незалежно від того, де він рендериться в дереві компонентів. Без порталів ви могли б спробувати досягти цього за допомогою абсолютного позиціонування та z-index, що може призвести до складних проблем зі стилізацією та потенційних конфліктів. З порталами ви можете безпосередньо рендерити вміст модального вікна в певний вузол DOM, такий як спеціальний елемент "modal-root", забезпечуючи його рендеринг завжди на правильному рівні.

Навіщо використовувати портали React?

Портали React вирішують кілька поширених проблем у веб-розробці:

Як реалізувати портали React

Використання порталів React є простим. Ось покрокова інструкція:

  1. Створіть вузол DOM: Спочатку створіть вузол DOM, куди ви хочете рендерити вміст порталу. Зазвичай це робиться у вашому файлі `index.html`. Наприклад:
    <div id="modal-root"></div>
  2. Використовуйте `ReactDOM.createPortal()`: У вашому компоненті React використовуйте метод `ReactDOM.createPortal()` для рендерингу вмісту в створений вузол DOM. Цей метод приймає два аргументи: вузол React (вміст, який ви хочете рендерити) та вузол DOM, куди ви хочете його рендерити.
    import ReactDOM from 'react-dom';
    
    function MyComponent() {
      return ReactDOM.createPortal(
        <div>Цей вміст рендериться в modal-root!</div>,
        document.getElementById('modal-root')
      );
    }
    
    export default MyComponent;
  3. Рендеринг компонента: Рендерте компонент, що містить портал, так само, як і будь-який інший компонент React.
    function App() {
      return (
        <div>
          <h1>Мій застосунок</h1>
          <MyComponent />
        </div>
      );
    }
    
    export default App;

У цьому прикладі вміст `MyComponent` буде відрендерений всередині елемента `modal-root`, хоча `MyComponent` рендериться всередині компонента `App`.

Приклад: Створення модального компонента з порталами React

Давайте створимо повний модальний компонент, використовуючи портали React. Цей приклад включає базову стилізацію та функціональність для відкриття та закриття модального вікна.

import React, { useState } from 'react';
import ReactDOM from 'react-dom';

const modalRoot = document.getElementById('modal-root');

function Modal({ children, onClose }) {
  const [isOpen, setIsOpen] = useState(true);

  const handleClose = () => {
    setIsOpen(false);
    onClose();
  };

  if (!isOpen) return null;

  return ReactDOM.createPortal(
    <div className="modal-overlay">
      <div className="modal">
        <div className="modal-content">
          {children}
        </div>
        <button onClick={handleClose}>Закрити</button>
      </div>
    </div>,
    modalRoot
  );
}

function App() {
  const [showModal, setShowModal] = useState(false);

  const handleOpenModal = () => {
    setShowModal(true);
  };

  const handleCloseModal = () => {
    setShowModal(false);
  };

  return (
    <div>
      <h1>Мій застосунок</h1>
      <button onClick={handleOpenModal}>Відкрити модальне вікно</button>
      {showModal && (
        <Modal onClose={handleCloseModal}>
          <h2>Вміст модального вікна</h2>
          <p>Це вміст модального вікна.</p>
        </Modal>
      )}
    </div>
  );
}

export default App;

У цьому прикладі:

Вам також потрібно буде додати деякі стилі CSS до класів `modal-overlay` та `modal`, щоб правильно позиціонувати модальне вікно на екрані. Наприклад:

.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.modal {
  background-color: white;
  padding: 20px;
  border-radius: 5px;
}

.modal-content {
  margin-bottom: 10px;
}

Обробка подій з порталами

Одним з важливих аспектів при використанні порталів є обробка подій. Спливання подій (event bubbling) працює з порталами інакше, ніж зі стандартними компонентами React.

Коли подія відбувається всередині порталу, вона буде спливати вгору по дереву DOM, як зазвичай. Однак система подій React розглядає портал як звичайний вузол React, що означає, що події також будуть спливати вгору по дереву компонентів React, яке містить портал.

Іноді це може призвести до несподіваної поведінки, якщо ви не будете обережними. Наприклад, якщо у вас є обробник подій на батьківському компоненті, який повинен спрацьовувати тільки на події всередині цього компонента, він може також спрацювати на події всередині порталу.

Щоб уникнути цих проблем, ви можете використовувати метод `stopPropagation()` на об'єкті події, щоб запобігти подальшому спливанню події. Альтернативно, ви можете використовувати синтетичні події React та умовний рендеринг для контролю над тим, коли спрацьовують обробники подій.

Ось приклад використання `stopPropagation()`, щоб запобігти спливанню події до батьківського компонента:

function MyComponent() {
  const handleClick = (event) => {
    event.stopPropagation();
    console.log('Клікнуто всередині порталу!');
  };

  return ReactDOM.createPortal(
    <div onClick={handleClick}>Цей вміст рендериться в порталі.</div>,
    document.getElementById('portal-root')
  );
}

У цьому прикладі клік по вмісту всередині порталу викличе функцію `handleClick`, але подія не спливатиме до будь-яких батьківських компонентів.

Найкращі практики використання порталів React

Ось кілька найкращих практик, які слід пам'ятати при роботі з порталами React:

Альтернативи порталам React

Хоча портали React є потужним інструментом, існують альтернативні підходи, які можна використовувати для досягнення подібних результатів. Деякі поширені альтернативи включають:

Вибір підходу залежить від конкретних вимог вашого застосунку та складності елементів UI, які ви намагаєтеся створити. Портали, як правило, є найкращим варіантом, коли вам потрібен точний контроль над позиціонуванням та порядком накладання елементів і ви хочете уникнути конфліктів CSS.

Глобальні аспекти

При розробці застосунків для глобальної аудиторії важливо враховувати такі фактори, як локалізація, доступність та культурні відмінності. Портали React можуть відігравати роль у вирішенні цих питань:

Беручи до уваги ці глобальні аспекти, ви можете створювати більш інклюзивні та зручні для користувача застосунки для різноманітної аудиторії.

Висновок

Портали React — це потужний та універсальний інструмент для рендерингу вмісту поза стандартним деревом компонентів. Вони надають чисте та елегантне рішення для поширених патернів UI, таких як модальні вікна, підказки та спливаючі вікна. Розуміючи, як працюють портали, та дотримуючись найкращих практик, ви можете створювати більш гнучкі, легкі в обслуговуванні та доступні застосунки на React.

Експериментуйте з порталами у власних проєктах та відкривайте для себе безліч способів, якими вони можуть спростити ваш робочий процес розробки UI. Не забувайте враховувати обробку подій, доступність та глобальні аспекти при використанні порталів у виробничих застосунках.

Опанувавши портали React, ви зможете підняти свої навички React на новий рівень та створювати більш складні та зручні для користувача веб-застосунки для глобальної аудиторії.