[Gutenberg]親ブロックの値を子ブロックに伝える

[Gutenberg]入れ子構造の記事で入れ子にできるブロックを制作しましたが、ときには親ブロックから子ブロックへ値を渡したい事があります。

この記事では親でパネル形式を指定する事で子供パネルを一気に変更する事が出来るような商品一覧を想定したブロックを制作しながら解説していきます。

目次

親ブロックを制作する

親ブロックは商品を一覧で表示するためのフレームの役割をします。

サイドバーから商品パネルの表示形式を「リスト」と「パネル」の2つを選択することが可能にし、選択肢によって子コンポーネントである商品パネルにその選択した情報を渡し、子コンポーネントの方で表示形式を変更します。

親ブロックの名前はproduct-listにします。

product-listブロックのひな形を用意します。

product-list
└── src
    ├── index.js
    ├── edit.js
    ├── save.js
    └── block.json

edit.js

edit.jsに以下のようにコードを記載します。

import { InspectorControls, InnerBlocks, useBlockProps } from '@wordpress/block-editor';
import { PanelBody, RadioControl } from '@wordpress/components';


export default function Edit({ attributes, setAttributes }) {
  const { type } = attributes;

  const blockProps = useBlockProps();

  const ALLOWED_BLOCKS = ['create-block/product-panel'];

  const onTypeChange = (type) => {
    setAttributes({ type });
  };


  return (
    <>
      <InspectorControls>
        <PanelBody title={'表示タイプ'}>
          <RadioControl
            selected={type}
            options={[
              { label: 'リスト形式', value: 'list' },
              { label: 'パネル形式', value: 'panel' },
            ]}
            onChange={onTypeChange}
          />
        </PanelBody>
      </InspectorControls>
      <div {...blockProps}>
        <InnerBlocks
          allowedBlocks={ ALLOWED_BLOCKS }
        />
      </div>
    </>
  );
};

これでサイドバーに「表示タイプ」というラジオボタンの選択肢が表れ、リスト形式で表示するのかパネル形式で表示するのかを選ぶ事が可能となります。

親から子へ値を渡す処理は後程実装します。

block.js

表示タイプをtypeというコメントデリミタに保存します。

block.jsonのattributesに追加します。

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 2,
	"name": "create-block/product-list",
	"version": "0.1.0",
	"title": "product-list",
	"category": "widgets",
	"icon": "smiley",
	"description": "Example static block scaffolded with Create Block tool.",
	"supports": {
		"html": false
	},
	"attributes": {
		"type": {
			"type": "string",
			"default": "list"
		}
	},
	"textdomain": "block-tut",
	"editorScript": "file:./index.js",
	"editorStyle": "file:./index.css",
	"style": "file:./style-index.css"
}

子ブロックを制作する

今回はサンプルですので画像、タイトル、説明文と、決まった値をセットしたブロックを制作します。

実際に使用する場合はそれぞれ編集が可能にしたり、記事を直接引っ張って表示したりします。

まずひな形を用意します。今回はproduct-panelにします。

product-panel
└── src
    ├── index.js
    ├── edit.js
    ├── save.js
    └── block.json

edit.js

edit.jsに以下のコードを記載します。

import { useBlockProps } from '@wordpress/block-editor';


export default function Edit() {

  const blockProps = useBlockProps();

  return (
    <>
      <div {...blockProps}>
        <img src="#" alt="" />
        <div>
          <h3>タイトル</h3>
          <p>説明文 ... </p>
        </div>
      </div>
    </>
  );
};

親から子へ値を渡す処理

親から子へ値を渡すためには今持っている子供のブロックのIDを取得し、その子ブロックへIDを指定してAttributをアップデートする事で子ブロックで値を受け取る事が可能です。

Attributをアップデートとはblock.jsonに記載しているAttributです。

block.jsonのattributに保存している値を親から直接変更するという事ですね。

ですのでまずはブロックのIDを取得しましょう。

入れ子になっているブロックのIDを取得する方法

親ブロックのedit.jsを開きます。

子ブロックの情報は引数のclientIdから取得する事が可能ですので引数にclientIdを追加します。

export default function Edit({ attributes, setAttributes, clientId }) {};

clientIdから実際に子ブロックの情報を引き出すにはselectを使用します。

selectをインポートします。この後、通知のためにdispatchも使用するので合わせてインポートしておきましょう。

import { dispatch, select } from "@wordpress/data";

次に実際に子ブロックへ値を伝える処理になります。

const children = select('core/block-editor').getBlocksByClientId(clientId)[0].innerBlocks;
children.forEach(function(child){
	dispatch('core/block-editor').updateBlockAttributes(child.clientId, {type: type});
});

まず、selectにcore/block-editorという引数を渡しgetBlocksByClientIdを実行します。

getBlocksByClientIdにclientIdを渡す事で情報を取得可能です。

id情報は0番目のinnerBlocksに入っています。

取得した値をchildrenへ格納し、forEachで全てを取り出します。

dispatchを使用して渡したい値であるtypeをtypeという名前で渡す事で完了です。

この受け渡し処理は値の変更の度に行ってほしいです。

ですのでEdit関数の中にそのまま(関数などにはまとめず)記載しましょう。

最終的なコードは以下のようになります。

import { InspectorControls, InnerBlocks, useBlockProps } from '@wordpress/block-editor';
import { PanelBody, RadioControl } from '@wordpress/components';
import { dispatch, select } from "@wordpress/data";


export default function Edit({ attributes, setAttributes, clientId }) {
  const { type } = attributes;

  const blockProps = useBlockProps();

  const ALLOWED_BLOCKS = ['create-block/product-panel'];

  const onTypeChange = (type) => {
		setAttributes({ type });
	};

  const children = select('core/block-editor').getBlocksByClientId(clientId)[0].innerBlocks;
  children.forEach(function(child){
    dispatch('core/block-editor').updateBlockAttributes(child.clientId, {type: type});
  });

  return (
    <>
      <InspectorControls>
        <PanelBody title={'表示タイプ'}>
          <RadioControl
            selected={type}
            options={[
              { label: 'リスト形式', value: 'list' },
              { label: 'パネル形式', value: 'panel' },
            ]}
            onChange={onTypeChange}
          />
        </PanelBody>
      </InspectorControls>
      <div {...blockProps}>
        <InnerBlocks
          allowedBlocks={ ALLOWED_BLOCKS }
        />
      </div>
    </>
  );
};

Reactは値の変更があるたびに関数が実行されます。(Edit関数)

ですので関数のrootにちょくせす記載する事で値の変更時に毎回通知させる事が可能となります。

子ブロックで値を受け取る

子ブロックでの値の受け取りは簡単です。

block.jsonに値を保存しておくtypeをattributesに追加します。

親でdispatchされるとこのtypeに値が保存されます。

typeに保存されるのは親ブロックのupdateBlockAttributesの第二引数でtypeを指定したからです。

他の値を指定すればtype以外に保存する事も可能です。

あとは通常通り、edit関数の引数からattributesを取得し、attributes.typeで受け取る事が可能です。

sava.jsも同じです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

プログラムちょと書ける。
いまはバリ島でスクール作っている。
プログラムちょっとできる。

目次