Две лучшие практики создания модалов в React 18


Оглавление

  • Начальный проект
  • Использование пользовательских хуков для легкого показа и скрытия модалов
    • В чем проблема?
    • Что такое пользовательский хук?
    • Переписывание нашего модала с помощью пользовательского хука
  • Использование React Portal
    • В чем проблема?
    • Что такое реакт-портал
    • Использование create Portal
  • Окончательный проект

Начальный проект

Мы начнем с простого проекта create-react-app, который состоит только из двух компонентов, один из которых — наш основной компонент App, а другой — компонент Modal. (Этот проект также можно найти в этой репозитории Github).

Как вы можете видеть, компонент Modal использует флаг (show), который приходит из родительского компонента в качестве параметра, чтобы проверить, должен ли он отображаться или нет. Он также посылает родительскому компоненту событие нажатия на кнопку закрытия, чтобы сообщить ему, что пора переключить флаг:

const Modal = ({ show, onCloseButtonClick }) => {
  if (!show) {
    return null;
  }

  return (
    <div className="modal-wrapper">
      <div className="modal">
        <div className="body">Click on the close button to close the modal.</div>
        <div className="footer">
          <button onClick={onCloseButtonClick}>Close Modal</button>
        </div>
      </div>
    </div>
  );
};

export default Modal;

Войти в полноэкранный режим Выйти из полноэкранного режима

В компоненте App, однако, используется состояние, которое передается в качестве параметра Modal. Кроме того, App прослушивает событие click кнопки close в Modal и устанавливает состояние/флаг в false всякий раз, когда происходит событие click или, другими словами, закрывает модал:

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

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

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

  return (
    <div className="App">
      <Modal show={showModal} onCloseButtonClick={closeModal} />
      <div className="button" onClick={openModal}>Open Modal</div>
    </div>
  );
}
Вход в полноэкранный режим Выход из полноэкранного режима

 
 

Использование пользовательских хуков для легкого отображения и скрытия модалов

 

В чем проблема?

Проблема этого метода заключается в том, что каждый раз, когда вам нужно использовать модальный режим, вам приходится повторяться, добавляя одно состояние в качестве флага (showModal), и два метода, которые отвечают за переключение состояния (openModal() и closeModal()):

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

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

const closeModal = () => {
  setShowModal(false);
}
Вход в полноэкранный режим Выход из полноэкранного режима

Однако в этом разделе мы увидим, что с помощью простого пользовательского хука вам больше не придется добавлять эту кучу повторяющегося кода.

 

Что такое пользовательский хук?

React Hooks — это мощные инструменты, появившиеся в React 16, и мы уже использовали их выше для создания нашего единственного состояния (showModal). Пользовательские хуки, с другой стороны, это просто хуки, созданные вами, и вы можете использовать их для извлечения логики компонентов в многократно используемые функции.

Согласно официальному определению:

Пользовательский хук — это функция JavaScript, имя которой начинается с «use» и которая может вызывать другие хуки.

 

Переписывание нашего модала с помощью пользовательского хука

Как я уже говорил, в нашем проекте мы повторяем логику использования Modal, и теперь мы можем использовать наш пользовательский хук, чтобы сохранить логику.

Шаг 1: Создание
Чтобы назвать наш пользовательский хук, мы уже знаем, что имя пользовательского хука должно начинаться с use, и поскольку мы создаем этот пользовательский хук для нашего Modal, мы можем просто назвать его useModal:

const useModal = () => {

}

export default useModal;

Вход в полноэкранный режим Выйти из полноэкранного режима

Шаг 2: Добавить
Мы уже знаем о повторяющейся логике для модала, нам нужно состояние и функция для его переключения. Поскольку эта логика уже существует в компоненте App, мы можем просто вырезать и вставить ее в наш пользовательский хук:

import { useState } from 'react';

const useModal = () => {
    const [isShowing, setIsShowing] = useState(false);

    function toggle() {
        setIsShowing(!isShowing);
    }
}

export default useModal;

Войти в полноэкранный режим Выйти из полноэкранного режима

Шаг 3: Возврат
Теперь мы должны сделать состояние и функцию переключения доступными за пределами нашего пользовательского хука, и поскольку у нас есть две вещи для возврата, как и в стандартном хуке useState в библиотеке React, мы можем просто вернуть значения в виде массива:

import { useState } from 'react'

const useModal = () => {
    const [isShowing, setIsShowing] = useState(false);

    function toggle() {
        setIsShowing(!isShowing);
    }

    return [
        isShowing,
        toggle
    ];
}

export default useModal;
Войти в полноэкранный режим Выход из полноэкранного режима

Шаг 4: Использование
Теперь пришло время использовать наш великолепный пользовательский хук везде, где нам нужно использовать компонент Modal:

function App() {
  const [isShowingModal, toggleModal] = useModal();

  return (
    <div className="App">
      <Modal show={isShowingModal} onCloseButtonClick={toggleModal} />
      <div className="button" onClick={toggleModal}>Open Modal</div>
    </div>
  );
}
Войти в полноэкранный режим Выйти из полноэкранного режима

И вот результат:

 

Использование React Portal

 

В чем проблема?

Есть еще одна вещь, которую мы можем улучшить в нашем Modal. Вот как Modal отображается в DOM:

Как вы можете видеть, модал появляется внутри <div class="App"> просто потому, что мы поместили модал внутрь компонента App. Однако, действительно ли ему там место? Модал обычно считается компонентом, который находится вне иерархии DOM.

 

Что такое React Portal?

React Portal отображает наш компонент вне иерархии DOM родительского компонента. Вот как мы его используем:

ReactDOM.createPortal(child, container);
Войти в полноэкранный режим Выйти из полноэкранного режима

А теперь давайте посмотрим, как мы используем его в нашем Modal.

 

Использование создания портала

Эта часть очень проста. Единственное, что нам нужно сделать, это обернуть наш модал порталом:

import ReactDOM from 'react-dom';

const Modal = ({ show, onCloseButtonClick }) => {
  if (!show) {
    return null;
  }

  return ReactDOM.createPortal(
    <div className="modal-wrapper">
      <div className="modal">
        <div className="body">
          Click on the close button to close the modal.
        </div>
        <div className="footer">
          <button onClick={onCloseButtonClick}>Close Modal</button>
        </div>
      </div>
    </div>
    , document.body
  );
};

export default Modal;
Войти в полноэкранный режим Выйти из полноэкранного режима

Помните, что второй параметр (document.body) — это остальная часть DOM, которую вы должны передать, иначе вы получите ошибку.

А вот как выглядит наш Модал в DOM после использования Portal:

 

Окончательный проект

 

Вы также можете найти окончательный код в этом репозитории


Что вы думаете по этому поводу? Есть ли другой способ, который я не упомянул? Пожалуйста, сообщите мне об этом в комментариях ниже. Я не могу дождаться ответа. Спасибо

Оцените статью
devanswers.ru
Добавить комментарий