С Redux и хуками

Когда я начал работать с React, одним из моих первых заданий было создание модального диалогового окна для отображения в нем некоторых данных. Я потратил много времени на поиски в Google, как создать функцию, которую я мог бы вызвать для отображения какого-нибудь окна. Для меня это было естественным поступком. Даже VanillaJs позволяет вам просто вызвать функцию alert для отображения простого диалогового окна. Я не мог понять, почему в React все по-другому.

Но, как видите, React работает не так. Одна из основных концепций React заключается в том, что если у вас есть состояние, и оно не меняется, вы можете отображать страницу столько раз, сколько захотите, и она всегда будет выглядеть одинаково. Но вызов функции, которая будет отображать модальное окно, противоречит этому принципу. Модальное окно будет отображаться не в зависимости от состояния компонента, а в зависимости от вызова какой-либо функции.

Так как же нам это сделать?

Во-первых, давайте создадим компонент, который должен открывать модальное окно. У нас будет простой компонент с кнопкой, и при нажатии на кнопку мы захотим, чтобы открывалось окно подтверждения. На консоли появится сообщение "Давай сделаем это!" если confirm принят, и ничего не будет делать, если confirm будет отменен.

Довольно просто, правда? Но теперь давайте создадим собственный confirm модальный файл и избавимся от встроенного confirm. Что мы сделаем, так это добавим состояние к компоненту, добавим флаг с именем openConfirm и отрендерим наш собственный компонент на основе этого. Затем мы предоставим метод, который должен вызываться при подтверждении в качестве опоры для нашего модального компонента.

Мы также должны создать наш CustomConfirm компонент с некоторым индивидуальным стилем и правильной привязкой реквизита к кнопкам:

Вуаля, готово! Вот как вы создаете простые модальные окна в стиле React.

Но прежде чем мы начнем праздновать, давайте рассмотрим более сложную ситуацию. В нескольких проектах мне приходилось открывать разные модальные окна из разных частей приложений с некоторой загрузкой данных API для отдыха. Как вы, наверное, знаете, если вы хотите изменить состояние компонента из разных частей приложения в React, вы будете использовать глобальный поставщик состояния, такой как Flux или Redux. Чего вы, вероятно, не хотите, так это иметь отдельный редуктор для каждого модального окна, особенно если их у вас много.

Вот почему я создал общий модальный компонент, который отображает все разные модальные окна, заботясь об управлении состоянием Redux и открытии / закрытии модального окна. Давайте посмотрим, как вы можете сделать то же самое.

Поскольку этот подход будет тесно связан с магазином Redux, давайте начнем с него. Во-первых, нам нужен модальный редуктор, который будет содержать данные о нашем модальном окне и выполнять с ними операции. В общем, нам нужно два типа действий:

  • Открыть модальное окно заданного типа с заданными данными.
  • Закройте модальное окно.

Это довольно просто реализовать в редукторе:

Этот редуктор выполняет только две вещи: устанавливает данные, если отправлено действие OPEN_MODAL, или устанавливает состояние в null, если отправлено действие CLOSE_MODAL. Чтобы лучше понять, какие данные отправляются на OPEN_MODAL, давайте посмотрим на действия:

Как видите, мы выполнили асинхронную операцию и получили некоторые данные (в данном случае profile). Затем мы отправляем действие OPEN_MODAL с типом модального окна, которое мы хотим отобразить, и любыми данными, которые мы хотим передать туда. Все, что нам нужно сделать сейчас, это использовать эти данные в компоненте, который будет обертывать все наши модальные окна:

Здесь мы связали наши модальные данные из глобального состояния с Modal компонентом. Мы также предоставляем функцию как опору, которая позволяет отправлять действие closeModal. Затем мы берем эти данные и визуализируем модальное окно.

<div className="modal">
...
</div>

Это наше модальное окно со всеми необходимыми стилями. В нем у нас есть проверка на modal.type. Исходя из этого, мы отображаем правильное модальное тело (в нашем случае ProfileModal). А затем у нас есть кнопка закрытия, которая позволяет нам закрыть окно. Конечно, в реальном приложении вы также можете добавить причудливый заголовок и нижний колонтитул. Все, что осталось сделать, это добавить компонент Modal к корневому компоненту нашего приложения, чтобы каждый раз, когда открывается какой-нибудь модальный файл, компонент Modal может отображаться. В моем случае я просто поместил его в App.js файл:

Как видите, все, что мы здесь сделали, это создали кнопку, которая отправляет действие openProfile, которое извлекает некоторые данные API, а затем открывает модальное окно.

Вот и все! Мы создали наш общий модальный компонент. Я знаю, что этот подход может показаться слишком сложным, чтобы отображать одно дурацкое модальное окно. Но, делая это таким образом и фактически следуя мышлению React, вы создадите приятные и чистые компоненты, которые легко использовать повторно и которые приятно тестировать.

Вы можете проверить все работающее приложение на GitHub.