ES2015+で静的DOMを記述するコツ

2021/02/14に公開

例えばReactで言うと下記のようなコードがあるとします。条件分岐やループを使って記述された、普通のDOMです。

import * as React from "react";

const flag = true;
const days = ['月','火','水'];
const undefinedable = undefined;

export const AppComponent = ({name}) => {
  return <div>
    <p>こんにちは{name}さん</p>
    { flag && <p>ふらぐ!</p> }
    <ul>
      { days.map(day => <li key={day}>{day}</li>) }
    </ul>
    <p>無いかも知れない値{undefinedable}</p>
  </div>
};

このようなJavaScriptで記述するDOM構造を、なんらかの理由でReact等のライブラリを使わず、InnerHTMLとして挿入する静的な文字列で書き換えたいとします。なお、すべての変数は一度Renderされた後に変更はされない物とします。

筆者の経験として、こういった作業はECMAScript5の時代にやった覚えはあるのですが、2021年現在だったらどうやって実装するかを書いていきます。

動作環境

  • React 17
  • Chrome 88

JavaScriptでの実装

テンプレート文字列の利用

テンプレートリテラル (テンプレート文字列)を使うことで、改行やプレースホルダーによる変数展開ができるようになります。基本的に、+演算子で文字列結合をしていく必要はもうありません。

export const AppHTML = (name) => {
  return `
    <div>
      <p>こんにちは${name}さん</p>
    </div>
  `;
};

これだけでも、かなり普通のDOMのように記述していくことができるように感じます。Reactのコードを貼り付けて{...}の前に$を付ければ、ある程度そのまま動くと思います。

VS Code拡張機能によるシンタックスハイライト

テンプレート文字列はあくまで文字列です。文字列内部のDOMがどれだけHTMLの見た目をしていても、シンタックスハイライトは効きません。

ですがVS Codeにはes6-string-htmlという拡張機能があり、導入することで文字列内部のHTMLにシンタックスハイライトを効かせる事ができます。

導入前

導入後

VS Code以外のエディタでも同様の拡張機能はあると思うので探してみてください。

Render

記述したDOMは、ReactだったらReactDOM.render()で描画されます。対して、静的な文字列をDOMとして埋め込むにはgetElementById等で適当なDOM要素を取ってきてelement.innerHTMLでセットするだけです。

import { AppComponent, AppHTML } from "./App";

// React
import * as React from "react";
import { render } from "react-dom";

const rootElement = document.getElementById("component_root");
render(<AppComponent name="リアクト" />, rootElement);

// innerHTML
const rootHTMLElement = document.getElementById("html_root");
rootHTMLElement.innerHTML = AppHTML("インナーエイチティエムエル");

条件分岐の表現

先程紹介したテンプレート文字列を使えば簡単です。一見ほぼReactと一緒ですね。

`${ flag && `<p>ふらぐ!</p>` }`

ループの表現

JavaScriptの配列を暗黙的に文字列へ変換すると,で結合されるため、空文字列で明示的に結合する必要があります。

export const AppHTML = (name) => {
  return `
    <ul>
      ${ days.map(day => `<li>${day}</li>`).join('') }
    </ul>
  `;
};

undefinedの扱い

Reactの場合、適当な変数がundefinedだった場合、空文字列''で表示されます。

// React
export const AppComponent = ({name}) => {
  return <p>無いかも知れない値{undefinedable}</p>;
};

対して、普通のJavaScriptでは'undefined'という文字列が表示されてしまいます。もし空文字列であることを期待する場合は注意が必要です。

export const AppHTML = (name) => {
  return `<p>無いかも知れない値${undefinedable ? undefinedable : ''}</p>`;
};

結論

最終的には下記のようになります。

export const AppHTML = (name) => {
  return `<div>
    <p>こんにちは${name}さん</p>
    ${ flag && `<p>ふらぐ!</p>` }
    <ul>
      ${ days.map(day => `<li>${day}</li>`).join('') }
    </ul>
    <p>無いかも知れない値${undefinedable ? undefinedable : ''}</p>
  </div>`;
};

完成品はCodeSandboxにもあります。

まとめ

React等を使ったリッチな開発体験のぬるま湯に浸かりきっていた所に冷水を浴びる良い経験でした。

Discussion