Создание пользовательского блока Гутенберга. Часть 7. Создание собственных пользовательских компонентов
registerBlockType()
До сих пор в этой серии руководств мы писали весь код внутри edit
функции. Это вполне возможно, и часто рекомендуется вместо этого назначать редактирование отдельному компоненту. Таким образом, мы можем использовать такие функции, как состояние компонента и методы жизненного цикла. Кроме того, он намного чище, читабельнее и содержит многоразовый код!
Если вы не знакомы с созданием компонентов React или с методами состояния и жизненного цикла, я рекомендую сначала прочитать официальное руководство React по этой теме.
Определение компонента класса дляedit
Вы можете определить компонент либо как функцию, либо как класс. С компонентом класса вы можете использовать такие функции, как, например, методы состояния и жизненного цикла. Однако в более новых версиях React (16+) вы можете использовать хуки React для имитации состояний и методов жизненного цикла внутри функциональных компонентов. Но в этом уроке мы сосредоточимся на создании компонента класса. То, что мы создали до сих пор в этой серии, «встроенные» в registerBlockType()
for edit
и save
, являются функциональными компонентами.
Для определения компонента класса мы расширяем WordPress Component
(в wp.element
пакете), точно так же, как вы расширяете компонент класса до React.Component
.
Имейте в виду, что ваш компонент класса должен включать функцию render()
. И из-за того, как работает Javascript, ваш класс должен быть определен до вашего registerBlockType()
вызова (сначала напишите компонент вашего класса в файле и сохраните registerBlockType()
после него. Позже в этом посте мы узнаем, как разделить компоненты в отдельные файлы, экспортировать и включать их).
Короче, примерно так:
Реквизит from edit
автоматически применяется к нашему компоненту. Не забывайте, что компоненту класса нужно ссылаться на props с помощью this.props
. В ядре WordPress Gutenberg принято использовать отдельные компоненты для edit
функций, поскольку они чаще всего содержат намного больше кода. Функцию save
часто можно оставить, registerBlockType()
если только она не содержит много кода.
Сделав это, вы теперь можете написать свой компонент так же, как в React. Вы можете добавлять функции, конструктор, методы состояния и жизненного цикла.
Это код, который мы получили на последнем шаге, преобразованный в компонент класса:
Если вы деструктурировали attributes
и setAttributes
из реквизита, как мы, все, что вам нужно изменить при переходе в отдельный компонент класса, это изменить одну строку; #9
от props
до this.props
. Весь код будет работать так же, как и раньше, ничего не исправляя. В этом красота деструктурирования. Если вы не деструктурировали его и ссылались, например props.attributes
, напрямую, вам нужно было бы добавить this.
перед всеми отдельными ссылками на attributes
и setAttributes
везде.
Давайте начнем делать то, что мы теперь можем делать с компонентом класса!
Определение функций иthis
Конечно, да, вы можете определять функции внутри edit
функционального компонента перед вызовом return
. Но лично я всегда предпочитал разделять функциональность по логике. Я считаю, что лучше отделить функции для логики и других целей вне функций, отвечающих за рендеринг вывода. Некоторые люди также предпочитают вызывать функции в событиях вместо того, чтобы делать их встроенными, как мы делали до сих пор (например, делали setAttributes()
) onChange
.
На данный момент в нашем коде есть две вещи, которые было бы полезно перенести в функции; InspectorControls
и BlockControls
. Это значительно сократит наш return
код и облегчит его чтение.
Мы определяем две функции, которые возвращают весь InspectorControls
блок и весь BlockControls
блок. С помощью стрелочных функций (functionName =() => { ... }
) у нас есть полный доступ к this
свойствам. Если вы не выполнили последнюю часть шага 1 — настроили Babel с новейшим синтаксисом, вы получите ошибки компиляции. Вам придется прибегнуть к созданию конструктора и привязки this
для каждой функции. Вы можете прочитать больше об обработке this
в начале страницы часто задаваемых вопросов React.
Также помните, что, поскольку мы находимся в классе, вам нужно вызывать все его функции this.
впереди.
Обратите внимание, что я исключил фактическое содержимое InspectorControls
и BlockControls
, чтобы сделать код короче. В их коде ничего не нужно менять.
Мы также используем тот факт, что return
оператор также может возвращать массив. Все в массиве будет отображаться как обычно в том порядке, в котором они находятся. Это упрощает нам вызов функций непосредственно внутри return
инструкции.
Очевидно, вы также можете определить методы жизненного цикла, такие как componentDidMount()
. В компонентах Gutenberg нет никакой разницы, чем в React.
Конструктор и использование состояния
Попробуем реализовать состояние в нашем компоненте. Имейте в виду, что состояние — это то, что временно хранится в нашем компоненте класса и нигде не сохраняется, например, в атрибутах. Это просто для того, чтобы контролировать — ну — состояние вашего компонента. Обычное использование состояния — это использование состояния в качестве флага состояния при ожидании возврата асинхронного вызова, сохранение счета чего-то временного перед сохранением его в атрибуте или реализация блочных «режимов предварительного просмотра/редактирования».
Вы ссылаетесь на состояние и состояние обновления точно так же, как в React; с this.state
и setState()
. Обычно вы инициализируете состояние в конструкторе. А что касается определения конструктора — это точно так же, как в React — не забудьте также передать props
и сделать super(props)
. Короче говоря:
class FirstBlockEdit extends Component {
constructor(props) {
super(props);
this.state = {
example: 1
}
}
render() {
this.setState({ example: 2 });
console.log(this.state.example);
...
Переключатель режима блокировки/редактирования
Давайте используем то, что мы узнали на предыдущем шаге в Панели инструментов, чтобы создать «переключатель режимов» для нашего блока. Мы реализуем панель инструментов с кнопкой, которая переключает состояние между режимом предварительного просмотра и режимом редактирования. В режиме редактирования блок, как обычно, получает два компонента RichText. Но при переходе в режим предварительного просмотра мы отключили редактирование и визуализацию вывода блока.
Сначала мы создаем конструктор и устанавливаем состояние с одним логическим свойством; editMode
который начинается как true
. Это super(props)
необходимо при определении конструктора в компоненте React на основе классов.
class FirstBlockEdit extends Component {
constructor(props) {
super(props);
this.state = {
editMode: true
}
}
...
В нашей функции вывода тулбаров мы меняем созданную нами ранее кастомную кнопку (которая только что- console.log
то при нажатии на нее). В его onClick
опоре мы вызываем setState()
и отрицаем текущее editMode
логическое значение. Чтобы пользователю было легче понять, мы также переключаемся между значком кнопки и меткой. Например, когда активен режим предварительного просмотра, на кнопке отображается метка «Редактировать» и значок карандаша, который обычно принимается как редактирование.
И, наконец, внутри основного метода рендеринга для нашего блока мы можем делать то, что хотим. Эта часть действительно зависит от вас — вы делаете то же самое, что и мы с меткой и значком на кнопке выше. Мы добавляем два блока вывода, один, если this.state.editMode
это true
(который должен быть обычными редактируемыми RichText
компонентами), и другой, если это false
.
В качестве примера я использую два компонента WordPress из wp.components
; Placeholder
и Disabled
для режима предварительного просмотра. Компонент Placeholder
помещает ваш блок в красивую серую рамку, из которой становится ясно, что его нельзя редактировать. Имейте в виду, что к нему прилагается стиль, поэтому, если вам нужен идеальный предварительный просмотр, это может быть не для вас. И я также оборачиваю все внутри Disabled
компонента, который делает все внутри нередактируемым, недоступным для щелчка и перетаскивания. Это наша новая render()
функция в нашем компоненте:
Я также использую компонент Fragment
( wp.element
пакет), который совпадает с React.Fragment
. Если вы не знакомы с ним, мы заключаем в него вывод, когда не хотим добавлять дополнительные ненужные HTML-оболочки. В React все должно иметь корневой узел. Когда активен режим редактирования (строка #13
), мы выводим два RichText
компонента сразу друг за другом, поэтому нам нужен корневой узел вокруг них.
Когда режим предварительного просмотра активен (строка #29
), мы выводим значения двух RichText
компонентов. Как и в случае с save
, мы используем RichText.Content
для возврата их значения вместо маленького редактора.
Компонент Placeholder
поставляется в гибком стиле и по умолчанию с строкой flex-direction. Предоставление true
в реквизите isColumnLayout
изменяет его на столбец flex-direction (так что все складывается). Но, как упоминалось ранее, вы можете пропустить этот компонент и создать предварительный просмотр точно так же, как это было бы во внешнем интерфейсе.
И с этим у нас есть переключатель предварительного просмотра/редактирования блочного режима. Очевидно, вы можете настроить содержимое «режима редактирования», чтобы показать, например, управляющие входы или что-то еще.
Вы можете создать столько компонентов, сколько захотите, вы не ограничены только одним для edit
функции! Просто создайте дополнительные компоненты и включите их в return
заявление. На самом деле это идея React — создание инкапсулированных фрагментов кода, возможно, каждый из которых обрабатывает свое собственное состояние, и объединение их для создания сложных пользовательских интерфейсов.