Учебное пособие из четырех частей по созданию расширенного, доступного и многоразового модального окна ReactJS.

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

Итак, что будет охватывать эту часть учебника?

  1. Как начать базовый проект
  2. Включите состояние для нашего модального окна
  3. Создайте пользовательский интерфейс для модального окна с помощью ReactJS

Давай начнем!

Первым шагом к началу работы является настройка вашего проекта. Мы можем использовать create-react-app, чтобы получить наш шаблон локально, но для этого примера я буду использовать sandbox . Таким образом, вы сможете сразу перейти к написанному мной коду. Я учусь через прямое взаимодействие, и мне неудобно хранить различные проекты, основанные на обучении, на вашем локальном компьютере. Следуйте этому примеру здесь. У меня будет по одной песочнице для каждой части учебного проекта.

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

Когда вы создадите свой проект в песочнице, вы увидите что-то вроде следующего…

Я хочу изменить иерархию папок так, чтобы она больше напоминала правильно организованное приложение.

Теперь перейдем к самому интересному! Мы начинаем с того, что визуализируем модальное окно. Давайте поместим кнопку на страницу, и когда она будет нажата, мы хотим, чтобы модальное окно выскакивало и передавало нам привет!

Давайте отредактируем App.js, чтобы добавить его в нашу кнопку.

// Dependencies
import React from 'react';
// Stylesheet
import "../styles.css";
export default class App extends React.Component {
   onButtonClick = () => {
      console.log('ive been clicked!');
   }
   render () {
      return (
         <button onClick={this.onButtonClick}>Click Me</button>
      );
   }
}

Это покажет нашу кнопку на экране. При нажатии используйте инструменты разработчика, чтобы увидеть, что консоль показывает, что наш обработчик onClick работает.

Пришло время сделать эту кнопку более сложной. Мы хотим добавить в приложение некоторую отслеживаемость состояния, чтобы модальное окно знало, когда показать или скрыть. Мы хотим, чтобы модальное окно отображалось, когда кнопка Click Me задействована в первый раз, и скрывать, когда вид за пределами модальный.

Давайте внесем некоторые изменения, чтобы добиться этого. Сначала мы вводим состояние show и устанавливаем для нашего обработчика нажатия кнопки значение true для состояния show. Когда состояние показа истинно, наш «модальный» объект, который на данный момент представляет собой просто div с некоторым текстом, должен отображаться.

// Dependencies
import React from 'react';
// Stylesheet
import "../styles.css";
export default class App extends React.Component {
   constructor (props) {
      super(props);
      this.state = {
         show: false
      };
   }
   onButtonClick = () => {
      this.setState({ show: true });
   }
   render () {
      const { show = false } = this.state;
      return (
         <React.Fragment>
            <button onClick={this.onButtonClick}>Click Me</button>
            {
               show ? (
                   <div>Hello! I'm going to be the modal!</div>
               ) : null
            }
         </React.Fragment>
      );
   }
}

Милая! Похоже, это работает. Теперь, может быть, мы сможем поработать над модальным окном, это немного жаль. Сначала я буду изолировать модальное окно от пути components/containers/Modal.js, учитывая, что наша цель - обеспечить возможность многократного использования модального окна. Модальное окно будет принимать show как опору и иметь условие, чтобы проверить, не является ли show не истинным, чтобы отобразить null. Это позволяет нам абстрагироваться от вещей и позволяет модальному окну обрабатывать исключительно условия рендеринга.

// Dependencies
import React from 'react';
// Stylesheet
import '../../styles.css';
export default class Modal extends React.PureComponent {
   render () {
      const { show = false } = this.props;
      if (!show) {
         return null;
      }
      return (
         <div className='outerModal centerFlex'>
            Hello! I'm going to be the modal!
         </div>
      );
   }
}

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

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

<div className='outerModal flex centerFlex'>
<div className='innerModal flex centerFlex flexColumn'>
      Hello! I'm going to be the modal!
   </div>
</div>

Стиль включает фиксированное позиционирование для нашего серого цвета фона, мы включаем z-index, поэтому наш оверлей является первым наиболее кликабельным элементом. Наша внутренняя модальная форма центрирована относительно внешнего элемента, и мы гарантируем, что она прокручивается в направлении y (в случае, если в нашем модальном окне много внутреннего содержимого). Ниже я прикрепил снимок экрана с изображением стиля. Вы также можете видеть, что наше модальное окно справа начинает выглядеть так, как должно!

Затем нам нужно поведение, которое мы ожидаем от нашего модального окна, поскольку в настоящее время нет способа его закрыть. Способ приспособиться к этому - добавить обработчик onClick к внешнему div в нашем модальном компоненте. Этот обработчик кликов запускает функцию onClose, которую родительский компонент нашего модального окна предоставит в качестве опоры. Затем родительский объект (App.js) установит для состояния показа значение false!

Применяя это на практике, мы отредактируем наш Modal.js.

// Dependencies
import React from 'react';
// Stylesheet
import '../../styles.css';
export default class Modal extends React.PureComponent {
   onOutsideClick = () => {
      const { onClose } = this.props;
      onClose && onClose();
   }
   render () {
      const { show = false } = this.props;
      if (!show) {
         return null;
       }
      return (
         <div className='outerModal flex centerFlex' onClick={this.onOutsideClick}>
             <div className='innerModal flex centerFlex flexColumn'>
                  Hello! I'm going to be the modal!
             </div>
         </div>
      );
   }
}

А потом мы отредактируем наш App.js.

onModalClose = () => {
   this.setState({ show: false });
}
....
render () {
   ...
   return (
      <React.Fragment>
         <button onClick={this.onButtonClick}>Click Me</button>
         <Modal show={show} onClose={this.onModalClose} />
      </React.Fragment>
   );
}

А теперь… барабанная дробь, пожалуйста!

У нас есть работающий модальный код!

Осталось несколько вещей, которые нам нужно очистить. Если вы попытаетесь щелкнуть внутри модального окна, вы заметите, что оно закрывается. Мы не хотим такого поведения! Проблема здесь в том, что событие щелчка всплывает от внутреннего модального div к внешнему модальному div, а затем добавленный нами обработчик щелчков выполняет свою часть, чтобы закрыть модальное окно. Чтобы исправить это, мы используем stopPropagation в нашем внутреннем модальном div.

<div className='innerModal flex centerFlex flexColumn' onClick={this.stopPropagation}>...</div>

И наш обработчик в Modal.js

stopPropagation = (e) => {
   e && e.stopPropagation();
}

Теперь наше модальное окно не закрывается, когда вы нажимаете на его внутреннее содержимое.

Перед тем, как мы завершим первую часть, посвященную модальным окнам, у нас есть еще одна последняя деталь. Я хочу сделать еще одну абстракцию, прежде чем я буду удовлетворен. Одна деталь, которую мы хотим иметь для нашего модального окна, - это гибкость внутреннего содержимого. Давайте оставим определение содержимого модального окна родительскому компоненту. Чтобы обеспечить гибкость указания родителем внутреннего содержимого нашего модального окна, мы используем присущие ему свойства children, которые ReactJs передает всем элементам за нас. Этот метод следует стратегии сдерживания композиции, описанной в документации ReactJS.

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

export default class Modal extends React.PureComponent {
...
   render () {
      const { show = false, children } = this.props;
      return (
         <div className='outerModal flex centerFlex' onClick={this.onOutsideClick}>
            <div className='innerModal flex centerFlex flexColumn' onClick={this.stopPropagation}>
               { children }
            </div>
         </div>
      );
   }
}

App.js не должен быть родительским компонентом, отвечающим за предоставление внутреннего содержимого нашего модального окна, поэтому мы определим более конкретную модальную оболочку. Ради этого примера давайте назовем наш конкретный modalGreetingsModal.js, и он будет жить по пути components/primitives/GreetingsModal.js. GreetingsModal будет использовать теперь общий Modal и предоставлять соответствующий внутренний контент.

// Dependencies
import React from 'react';
// Containers
import Modal from '../containers/Modal';
// Stylesheet
import '../../styles.css';
export default class GreetingsModal extends React.PureComponent {
   render () {
      const { show = false, onClose } = this.props;
         return (
            <Modal show={show} onClose={onClose}>
                <span>Hello! I'm a modal!</span>
            </Modal>
         );
   }
}

Наконец, нам нужно указать App.js использовать наш новый GreetingsModal вместо общего Modal.

// Dependencies
import React from 'react';
// Components
import GreetingsModal from './primitives/GreetingsModal';
// Stylesheet
import "../styles.css";
export default class App extends React.Component {
   ...
   render () {
       ...
       return (
           <React.Fragment>
              <button onClick={this.onButtonClick}>Click Me</button>
              <GreetingsModal show={show} onClose={this.onModalClose} />
           </React.Fragment>
       );
   }
}

Больше ничего не нужно менять в App.js, мы передаем те же реквизиты, что и раньше, и обрабатываем все остальное так же. Возможно, мы также можем настроить GreetingsModal для управления состоянием нашего модального окна. Однако знание этого типа состояния на более высоком уровне дает свои преимущества. По мере того, как наш проект становится более сложным, у нас может появиться дополнительная логика, зависящая от этого состояния. Мы могли бы даже использовать другую библиотеку, такую ​​как Redux, для контейнеризации нашего состояния для нас.

Для справки - песочница первой части этого модального проекта.

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

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

Спасибо, что прочитали еще раз! ❤️