ReactからBlocklyを使ってみた

Qiita初投稿です。ReactでBlocklyエディタを表示させるまでの手順を紹介します。
使用環境はこんな感じ。

```
$ npm -v
6.14.8
$ create-react-app --version
3.4.1
```

# 1. create-react-appする
Reactプロジェクトの作成にはcreate-react-appを使用しました。

```
$ create-react-app blockly-react
(省略)
Happy hacking!
```

とりあえずちゃんと作成できているかテスト

```
$ cd blockly-react
$ npm start
```

自動的にブラウザが開いて以下の画面が出ていればOKです。
![スクリーンショット 2020-10-22 1.29.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365868/011f9aa3-1a15-f240-477b-6fa0bd67c365.png)

# 2. Blocklyのインストール
Blockly公式のnpmパッケージを入れます。

```
$ npm install blockly
```

記事を書いている時点ではこのバージョンが入りました。

```package.json
{
  "dependencies": {
    ...
    "blockly": "^3.20200924.3",
    ...
  },
}
```

# 3. App.jsの編集
App.jsに元々入っているコードは使わないので消し、まずは愚直に以下のコードで試してみます。

```jsx:App.js
import React, { useEffect } from 'react';
import Blockly from "blockly";

function App() {
    useEffect(() => {
        Blockly.inject("blocklyDiv", {
            toolbox: document.getElementById("toolbox")
        });
    });

    return (
        <div>
            <div id="blocklyDiv" style={{width: "1024px", height: "600px"}}></div>

            <xml id="toolbox" style={{display: "none"}}>
            <category name="Loops" colour="%{BKY_LOOPS_HUE}">
                <block type="controls_repeat_ext">
                    <value name="TIMES">
                        <block type="math_number">
                            <field name="NUM">10</field>
                        </block>
                    </value>
                </block>
                <block type="controls_whileUntil"></block>
            </category>
            <category name="Math" colour="%{BKY_MATH_HUE}">
                <block type="math_number">
                    <field name="NUM">123</field>
                </block>
            </category>
            <category name="Text" colour="%{BKY_TEXTS_HUE}">
                <block type="text"></block>
                <block type="text_print"></block>
            </category>
        </xml>

        </div>
    );
}

export default App;
```

`Blockly.inject`はblocklyDivやtoolboxの要素を参照するので、`useEffect`を使用することでDOMが更新された後に実行するようにしています。
![スクリーンショット 2020-10-22 1.51.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365868/8af3d73d-1051-1048-a468-0f4cb9558d54.png)
画面は問題なく出ていますが、Chromeのコンソールを見ると大量のWarningが...。
そのうちの1つは、
`Warning: The tag <xml> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.`
だそうです。
他のWarningも似たようなもので、xmlやcategory、blockなどのタグを使っているのが理由のようです。

# 4. Warningを消す

```jsx:App.js
import React, { useEffect } from 'react';
import Blockly from "blockly";

function App() {
    const xml = `
        <xml id="toolbox">
            <category name="Loops" colour="%{BKY_LOOPS_HUE}">
                <block type="controls_repeat_ext">
                    <value name="TIMES">
                        <block type="math_number">
                            <field name="NUM">10</field>
                        </block>
                    </value>
                </block>
                <block type="controls_whileUntil"></block>
            </category>
            <category name="Math" colour="%{BKY_MATH_HUE}">
                <block type="math_number">
                    <field name="NUM">123</field>
                </block>
            </category>
            <category name="Text" colour="%{BKY_TEXTS_HUE}">
                <block type="text"></block>
                <block type="text_print"></block>
            </category>
        </xml>
    `;

    const xmlParser = new DOMParser();
    const xmlDom = xmlParser.parseFromString(xml, "text/xml");

    useEffect(() => {
        Blockly.inject("blocklyDiv", {
            toolbox: xmlDom.getElementById("toolbox")
        });
    });

    return (
        <div>
            <div id="blocklyDiv" style={{width: "1024px", height: "600px"}}></div>
        </div>
    );
}

export default App;
```

jsx内に直接xmlを書くのではなく、文字列からパースするアプローチで行きました。
これでWarningも出ずにBlocklyエディタの画面も問題なく使えます。