JSXでGutenbergブロック開発

Gutenbergブロックの edit 関数や save 関数は返り値として React要素を返すため、その部分をJSXで記述することが可能です。JSXを導入することにより記述が容易になり、可読性の向上も見込めます。

// JSXなし
return wp.element.createElement(
  "h1",
  { className: "heading" },
  "Hello, World"
);
// JSXあり
return (
  <h1 className="heading">
    Hello, World
  </h1>
);

今回はGutenberg用備考ブロックを作るで作成したブロックの一部をJSXで書き直したいと思います。最終的なコードはGitLabで公開しているので興味があればご覧ください。

環境のインストール

JSXを使用できるようするにはまず作業環境を整える必要があります。トランスパイルに Babel を使用するため、Node.js をインストールしていない方はまずそちらをインストールします。こちらこちらの記事などを参考にして npm コマンドを使用できるようにしましょう。

npm コマンドが使えるようになったらBabelとJSX用プラグインをインストールします。必要なパッケージは @babel/core@babel/cli@babel/plugin-transform-react-jsx です。前回作成したプラグインディレクトリ my-note-plugin に移動し、以下のコマンドを実行しましょう。

$ npm install -D @babel/core @babel/cli @babel/plugin-transform-react-jsx

インストールが終わると以下のようなディレクトリ構成になっているはずです。

my-note-plugin/
  |- node_modules/
  |- note-block/
  |- my-note-plugin.php
  `- package-lock.json

これでインストール作業は終わりです。

Babelの設定と実行

Babelの設定は .babelrc に記述します。

{
  "plugins": [
    [
      "@babel/plugin-transform-react-jsx", {
        "pragma": "el"
      }
    ]
  ]
}

5行目の pragma にはReact要素を作成する関数名を指定します。例えばReactの場合は React.createElement、Gutenbergの場合は wp.element.createElement です。

ただ今回のプラグインでは var el = wp.element.createElement で関数名を省略しているため、el を指定しています。もちろんwp.element.createElement でも大丈夫です。

今回はトランスパイル元ファイルを my-note-plugin/note-block/src/index.js 、トランスパイル先ファイルを my-note-plugin/note-block/index.js にします。そのため現在の index.js を my-note-plugin/note-block/src に移動します。

$ mkdir note-block/src
$ mv note-block/index.js src

ここで一度トランスパイルしてみましょう。トランスパイルは以下のコマンドで行います。

$ npx babel note-block/src --out-dir note-block

Babelが正常にインストールされていれば note-block ディレクトリに index.js が生成されているはずです。

JSXに書き換え

では edit 関数と save 関数の戻り値をJSXで書き換えましょう。現在のコードでは edit 関数には createEditElement 関数、 save 関数には createSaveElement 関数がそれぞれ指定されているためそちらを変更します。

これを

function createEditElement( props ) {
  return el(
    'div', {
      className: name
    }, [
      el(
        wp.editor.RichText, {
          tagName: 'p',
          className: name + '__heading',
          value: props.attributes.heading,
          onChange: function( heading ) {
            props.setAttributes( { heading: heading } );
          }
        }
      ),
      el(
        wp.editor.RichText, {
          tagName: 'div',
          className: name + '__content',
          value: props.attributes.content,
          multiline: 'p',
          onChange: function( content ) {
            props.setAttributes( { content: content } );
          }
        }
      )
    ]
  );
}

こう。11行目から23行目がJSXです。

function createEditElement( props ) {
  var onChangeHeading = function( heading ) {
    props.setAttributes( { heading: heading } );
  }

  var onChangeContent = function( content ) {
    props.setAttributes( { content: content } );
  }

  return (
    <div className={name}>
      <wp.editor.RichText
        tagName="p"
        className={name + '__heading'}
        value={props.attributes.heading}
        onChange={onChangeHeading} />
      <wp.editor.RichText 
        tagName="div"
        className={name + '__content'}
        value={props.attributes.content}
        multiline="p"
        onChange={onChangeContent} />
    </div>
); }

同じように createSaveElement も

function createSaveElement( props ) {
  return el(
    'div', {
    }, [
      el(
        wp.editor.RichText.Content, {
          tagName: 'p',
          className: name + '__heading',
          value: props.attributes.heading
        }
      ),
      el(
        wp.editor.RichText.Content, {
          tagName: 'div',
          className: name + '__content',
          value: props.attributes.content
        }
      )
    ]
  );
}

書き換えます。

function createSaveElement( props ) {
  return (
    <div>
      <wp.editor.RichText.Content
        tagName="p"
        className={name + '__heading'}
        value={props.attributes.heading} />
      <wp.editor.RichText.Content
        tagName="div"
        className={name + '__content'}
        value={props.attributes.content} />
    </div>
  );
}

今回のケースではあまりメリットがないように見えますが、要素が入れ子になればなるほどJSXの恩恵を受けることができます。

最後にもう一度トランスパイルをして終了です。

$ npx babel note-block/src --out-dir note-block

おわり

npm を用意して、 Babel をインストールして、と環境構築がやや面倒ですが一度用意さえしてしまえばあとはコマンド一つでトランスパイルできるようになります。

関数で記述する方法は敷居は低いですがパッと見どうなっているかがわからず、一つ一つ見ていかないといけないのが精神的にあまり良くないですね。どうせなら気持ちよくコーディングしたいものです。まあ、JSX自体が気持ち悪いという意見もありますがそれはまた別のお話。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です