Изучаем Gutenberg — 5 часть — React 101

Хотя Gutenberg и сделан на React, код, который мы пишем для создания пользовательских блоков — нет, хотя он, конечно, напоминает компонент React.

Сделаем компонент «Обо мне»

Мы собираемся создать компонент React, который обновляет цвет фона страницы и вводный текст на основе данных, которые вы вводите в несколько полей. Мы собираемся изучить некоторые основные концепции state-driven JavaScript, которые пригодятся, когда мы углубимся в создание блока Gutenberg .

В итоге у нас должно получиться вот это:

Начало работы

Первое, что мы собираемся сделать, это запустить CodePen. CodePen можно использовать бесплатно, поэтому зайдите туда и создайте новый pen .

Далее мы собираемся добавить некоторые JavaScript-зависимости. Существует три экрана редактора — найдите JSэкран и нажмите кнопку настройки. Откроется модальное окно «Параметры пера», в котором вы найдете раздел «Add External Scripts/Pens». Справа внизу есть меню быстрого выбора. Откройте его.

В меню выберите React . После этого откройте меню и выберите ReactDOM. Вы увидите предварительно заполненные некоторые текстовые поля.

Наконец, нам нужно подключить наш код ES6, поэтому в меню «Препроцессор JavaScript»выберите « Babel» .

Нажмите большую кнопку Сохранить и закрыть .

Мы подключили основную библиотеку React JS и библиотеку ReactDOM. Это позволит нам писать нужный код.

Настройте CSS

Оформим стили для внешнего вида. Но сначала настроим CSS-редактор. Первое, что мы сделаем, это настроить его для компиляции Sass. Как и в случае с редактором JS, нажмите на кнопку настройки, которая снова вызовет модальное окно Pen Settings   — на этот раз с настройками CSS.

Вверху есть меню CSS Preprocessor . Выберите SCSS.

Когда это будет сделано, перейдите в Add External Stylesheets / Pens и вставьте следующие три ссылки в отдельные текстовые поля:

https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.css
https://fonts.googleapis.com/css?family=Work+Sans:300
https://rawgit.com/hankchizljaw/boilerform/master/dist/css/boilerform.min.css

Они сделают сброс стилей, шрифт и некоторые полезные стили форм .

Теперь, когда все готово, нажмите кнопку «Сохранить и закрыть» еще раз.

Добавим немного стилей

У нас все настроено, поэтому этот шаг должен быть легким. Вставьте следующий Sass в редактор CSS:

:root {
  --text-color: #f3f3f3;
}

* {
  box-sizing: border-box;
}

html {
  height: 100%;
  font-size: 16px;
}

body {
  height: 100%;
  position: relative;
  font-size: 1rem;
  line-height: 1.4;
  font-family: "Work Sans", sans-serif;
  font-weight: 300;
  background: #f3f3f3;
  color: #232323;
}

.about {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  color: var(--text-color);
  transition: all 2000ms ease-in-out;
  
  &__inner {
    display: flex;
    flex-direction: column;
    height: 100%;
    margin: 0 auto;
    padding: 1.2rem;
  }
  
  &__content {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    flex: 1 1 auto;
    font-size: 3rem;
    line-height: 1.2;
    
    > * {
      max-width: 30ch;
    }
  }
  
  &__form {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 2rem 0;
    width: 100%;
    max-width: 60rem;
    margin: 0 auto;

    @media(min-width: 32rem) {
      flex-direction: row;
      justify-content: space-between;
      padding: 2rem;
    }
    
    > * {
      width: 15rem;
    }
    
    > * + * {
      margin: 1rem 0 0 0;
      
      @media(min-width: 32rem) {
        margin: 0;
      }
    }
    
    label {
      display: block;
    }
  }
}

// Boilerform overrides 
.c-select-field {
  &,
  &__menu {
    width: 100%;
  }
}

.c-input-field {
  width: 100%;
}

.c-label {
  color: var(--text-color);
}

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

Погружение в React

Первое, что мы собираемся сделать, это дать React что-то, за что можно зацепиться. Вставьте это в HTML-редактор на CodePen:

<div id="root"></div>

Давайте начнем с кода нашего компонента, создав новый экземпляр компонента React, написав следующий JavaScript:

class AboutMe extends React.Component {
}

Этот код создает новый компонент AboutMe.

 Добавьте следующий код в скобках:

constructor(props) {
  super(props);
  
  let self = this;
};

У нас здесь происходит несколько вещей:

constructorэто метод, который вызывается, когда вы пишете new AboutMe(), или если вы пишете <AboutMe />в JSX. Это создает объект. Этот параметр props вы часто увидите в React. Это коллекция свойств, которые передаются в компонент. Например: если вы написали <AboutMe name="Andy" />, вы сможете получить к нему доступ в constructorс помощью props.name.

superэто то, как мы говорим классу, который мы расширили для создания его собственного constructor. Мы также передаем его props на тот случай, если какие-либо родительские компоненты должны получить к ним доступ.

let self = this— это способ контроля за контекстом this. Из-за того, что мы используем letselfбудут доступны только в constructorфункции.

Теперь, когда мы рассмотрели конструктор, давайте добавим еще немного кода. После let self = this;строки вставьте следующий код:

self.availableColors = [
  {
    "name": "Red",
    "value": "#ca3814"
  },
  {
    "name": "Blue",
    "value": "#0086cc"
  },
  {
    "name": "Green",
    "value": "#3aa22b"
  }
];

У нас есть массив объектов, которые определяют варианты выбора цвета. 

Определение класса и конструктор теперь должны выглядеть так:

class AboutMe extends React.Component {
  
  constructor(props) {
    super(props);
    
    let self = this;
    
    // Set a list of available colors that render in the select menu
    self.availableColors = [
      {
        "name": "Red",
        "value": "#ca3814"
      },
      {
        "name": "Blue",
        "value": "#0086cc"
      },
      {
        "name": "Green",
        "value": "#3aa22b"
      }
    ];
  };
}

Пока все довольно просто. Давайте двигаться дальше и установим некоторые начальные значения в state. Добавьте следующий код после закрытия self.availableColors:

// Set our initial reactive state values
self.state = {
  name: 'Foo',
  color: self.availableColors[0].value
};

Эта начальная настройка состояния позволяет компоненту отображать как имя, так и цвет при загрузке, что предотвращает его появление в неправильном виде.

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

Теперь, поскольку в этом единственном компоненте достаточно много разметки, мы собираемся скопировать всю эту часть в нашу функцию. Добавьте следующее под constructor:

render() {
  let self = this;
  
  return (
    <main className="about" style={ { background: self.state.color } }>
      <section className="about__inner">
        <article className="about__content">
          { self.state.name ? <p>Hello there. My name is { self.state.name }, and my favourite color is { self.getActiveColorName() }</p> : null }
        </article>
        <form className="[ about__form ] [ boilerform ]">
          <div>
            <label className="c-label" htmlFor="name_field">Your name</label>
            <input className="c-input-field" type="text" id="name_field" value={ self.state.name } onChange={ self.updateName.bind(self) } />
          </div>
          <div>
            <label className="c-label" htmlFor="color_field">Your favourite color</label>
            <div className="c-select-field">
              <select className="c-select-field__menu" value={ self.state.color } onChange={ self.updateColor.bind(self) } id="color_field">
                { self.availableColors.map((color, index) => {
                  return (
                    <option key={ index } value={ color.value }>{ color.name }</option>
                  );
                })}
              </select>
              <span className="c-select-field__decor" aria-hidden="true" role="presentation">▾</span>
            </div>
          </div>
        </form>
      </section>
    </main>
  );
};

В JSX можно вернуть только один элемент, который может иметь дочерние элементы. Поскольку весь наш код обернут в тег <main>, у нас все хорошо. В этом теге <main> есть выражение в атрибуте, как мы рассмотрели в части 2. Это выражение устанавливает цвет фона в качестве текущего активного цвета, установленного в нашем состоянии. Он будет обновляться, когда пользователь меняет цвет.

Внутри <article class="about__content">элемента вы заметите это:

{ self.state.name ? <p>Hello there. My name is { self.state.name }, and my favourite color is { self.getActiveColorName() }</p> : null }

Этот тернарный оператор проверяет, задано ли имя, и отображает либо предложение, содержащее имя, либо null. Возвращение nullв JSX — это то, как вы говорите ему ничего не визуализировать клиенту. 

Далее давайте посмотрим на привязку события:

<input className="c-input-field" type="text" id="name_field" value={ self.state.name } onChange={ self.updateName.bind(self) } />

Если вы не привязали событие к полю ввода, оно будет доступно только для чтения. React предупредит вас об этом в консоли.

Помните, selfравно this, так что мы привязываем функцию updateName к
событию ввода  onChange, но мы также привязываем self, так что когда мы внутри
функции updateNamethisбудет равно AboutMe, что является нашим компонентом.

Последнее, что мы собираемся рассмотреть в функции  render — это циклы. Вот фрагмент, который отображает меню цвета:

<select className="c-select-field__menu" value={ self.state.color } onChange={ self.updateColor.bind(self) } id="color_field">
  { self.availableColors.map((color, index) => {
    return (
      <option key={ index } value={ color.value }>{ color.name }</option>
    );
  }) }
</select>

Значение и настройка изменения такие же, как и у вышеприведенного элемента <input />, поэтому мы проигнорируем их и углубимся в цикл. Мы открыли выражение, в котором мы запускаем довольно стандартную функцию Array Map , но, что важно, она возвращает JSX на каждой итерации, что позволяет каждой опции рендериться с остальной частью JSX.

Подключаем все вместе

Теперь, когда мы разобрали основные аспекты работы компонента, нам нужно подключить его. Вы заметите, что наш CodePen в данный момент ничего не делает. Это из-за двух вещей:

  • Мы еще не прикрепили компонент к DOM
  • Мы не написали никаких методов, чтобы сделать его интерактивным

Давайте начнем с первого и добавим обработчики событий изменения. Добавьте следующее под функцией constructor:

updateName(evt) {
  let self = this;
  
  self.setState({
    name: evt.target.value
  })
};

updateColor(evt) {
  let self = this;
  
  self.setState({
    color: evt.target.value
  })
};

Эти две функции обрабатывают события onChange на <select>и <input>и устанавливают их значения в state с помощью функции React setState. Теперь, когда значения находятся в состоянии, все, на что они подписаны, будет обновляться автоматически. Это означает, что тернарный оператор, отображающий ваше имя и цвет фона, будет меняться в реальном времени при вводе / выборе.

Далее, добавим последний метод к нашему компоненту. Добавьте следующее в недавно добавленные методы обновления:

// Return active color name from available colors, based on state value
getActiveColorName() {
  let self = this;
  
  return self.availableColors.filter(color => color.value === self.state.color)[0].name;
};

Эта функция использует метод JavaScript массива filter. С ES6 мы можем выбирать элементы массива на основе их значения объекта в одну строку. Мы можем выбрать
имя активного элемента availableColorsи вернуть его обратно. Методы JavaScript-массива часто встречаются в экосистеме React.

Подключеник компонента к DOM

Последнее, что мы собираемся сделать, это присоединить наш компонент к DOM, используя ReactDOM . Мы говорим: «Привет, браузер, принеси мне элемент <div id="root"> и представь в нем этот компонент React». ReactDOM делает все это возможным.

ReactDOM — это умный пакет, который принимает изменения в ваших динамических компонентах React, вычисляет, что необходимо изменить в DOM, и применяет эти изменения наиболее эффективным способом. С помощью метода ReactDOM renderToString() вы также можете отрисоввывать компоненты React в статическую строку, которая затем может быть вставлена ​​на страницу с помощью кода на стороне сервера. Ссылки добавляются так, что если ваш клиентский интерфейс выбирает какой-нибудь серверный рендеринг React, он определит, какие необходимы компоненты, и автоматически сделает весь кусок статической разметки динамическим.

Добавьте это внизу редактора JS:

// Attach our component to the <div id="root"> element
ReactDOM.render(<AboutMe />, document.getElementById('root'));

Теперь вы заметите, что ваше окно предварительного просмотра вдруг ожило! Поздравляем — вы только что написали компонент React 🎉

See the Pen

Завершение

В этой части вы узнали о реактивном компонентном JavaScript, написав компонент React. Это имеет отношение к вашему обучению, потому что пользовательские блоки Gutenberg следуют настройке, очень похожей на компонент React. Теперь, когда вы лучше поняли, как работает компонент React, вы сможете понять, как работает пользовательский блок Gutenberg. С точки зрения Gutenberg React имеет отношение только к строительным блокам внутри админпанели. В Gutenberg React функционирует как средство подготовки разметки для сохранения в базе данных в
столбце post_content. Использование React на фронтенде WordPress для создания чего-то подобного будет отдельным от того, что мы будем делать в этой серии.

Далее в этой серии мы собираемся отредактировать нашу тему WordPress, чтобы мы могли построить наш собственный блок Gutenberg.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Scroll to top