😵

宣言的UIが何か分からなかったので調べてみた

2021/04/04に公開

経緯

『Front-End Study #5「2020 年代のフロントエンド」[1]』というものに参加した際に、宣言的 UI というワードが出てきて[2]、「宣言的な UI って何??」って感じだったので調べました。

この記事ではあくまでどんなものを宣言的 UI というのかをとりあげているだけなので、仮想 DOM とかについては触れません。

また、今回は宣言的 UI の例として Vue.js(OptionsAPI)を使っていますが、宣言的 UI がどんなものかを理解する上では知らなくても問題ないと思います!

今回の例

例えば
①.入力エリア値を入力する
②-1.入力した値が下部の「」という値が入力されました。「」部分に表示される
②-2.入力した値を文字数カウントする
というようなものを作るとします。

イメージ

「こんにちは」と入力されると、以下のようなコードになるイメージです。

<div>
  <input type="text" value="こんにちは" />
  <!-- 下部のpタグ内に動的に値が入る -->
  <p>「こんにちは」という値が入力されました。</p>
  <p>5</p>
</div>

宣言的 UI の誕生前

これを宣言的 UI の誕生前では以下のように書かれていました。

まず、このような HTML があるとします。

<div class="div">
  <input class="input" type="text" value="" />
  <p><!-- 入力した値が動的に入る -->」という値が入力されました。</p>
  <p><!-- 文字数カウントが入る --></p>
</div>

次に JS では、上記で挙げた
①.入力エリア値を入力する
②-1.入力した値が下部の「」という値が入力されました。「」部分に表示される
②-2.入力した値を文字数カウントする
を実現する為に色々とコードを書きます。

まずは input 要素を取得する

input要素取得
const input = document.querySelector(".input");

次に取得した input 要素でインプットイベントが発火したら、何かしらの関数を実行させる

input.addEventListener("input", inputFunc);

「何かしらの関数」には入力した値を反映させる処理と文字数カウント処理をさせる
が、その前に、その 2 つに必要な要素を取得する

p要素2つ取得
const p = document.getElementsByTagName("p");

入力した値を反映させる処理では、固定の文字列と入力した値を組み合わせます
文字数カウント処理では、文字列の長さを 2 番目の p 要素に入れます

入力した値を反映させる処理と文字数カウント処理
function inputFunc(event) {
  const message = event.target.value;
  // 入力反映
  const p1 = p[0];
  p.innerText = "「" + message + "」という値が入力されました。";

  // 文字数カウント
  const p2 = p[1];
  p2.innerText = message.length;
}

全体としてこんな感じ

const input = document.querySelector(".input");
input.addEventListener("input", inputFunc);

const p = document.getElementsByTagName("p");
function inputFunc(event) {
  const message = event.target.value;
  // 入力反映
  const p1 = p[0];
  p.innerText = "「" + message + "」という値が入力されました。";

  // 文字数カウント
  const p2 = p[1];
  p2.innerText = message.length;
}

これで入力エリアで入力があった際に、入力テキスト反映と文字数カウントが実現されます。
このコードは「〇〇をして〜」「次は〇〇して〜」「〇〇を作って〜」など命令的な記述と言えます。

宣言的 UI の誕生前の悩み

欲しい UI を実現する為には、別の場所で「あれして」「こうして」など命令を出さなければなりません。
これだと、"完成形の(求めている)UI"と"実現するためのコード"が分離していて分かりづらいというのが悩みの 1 つでした。

これくらい簡単な例だと、そこまで分かりづらさを感じないと思いますが、規模が大きくなるほどしんどくなります。

例えば、TODO アプリ。
追加ボタンを押す →「テキスト」「完了ボタン」「削除ボタン」「編集ボタン」の要素をそれぞれ作成 → それらをli要素の子要素として入れる →UI として表示
を実現するだけでも割と面倒で、完成形の UI の分かりづらさが生じます。

jQuery はこの DOM 操作を簡単にしたものですが、結局 UI と実現するためのコードが分離されていて面倒です。


遊びがてら vanillaJS で TODO アプリを作ってみました。
完成形 UI のイメージしずらさを体験したい方は参考にどうぞ。笑
https://github.com/akihiro07/vanillaJS-TODO

宣言的 UI の誕生

そこで宣言的 UI の誕生です。
宣言的 UI で"完成形の(求めている)UI"を"実現するためのコード"でそのまま書けるようになりました。

Vue.js を使用すると、
①.入力エリア値を入力する
②-1.入力した値が下部の「」という値が入力されました。「」部分に表示される
②-2.入力した値を文字数カウントする
の実現は以下のようになります。

まずは UI 部分。

template
<template>
  <div>
    <input type="text" :value="message" @input="inputFunc">

    <p>「{{ message }}」という値が入力されました。</p>
    <p>{{ message.length }}</p>
  </div>
</template>

次に JS 部分。

script
export default {
  data() {
    return {
      message: ""
    };
  },
  methods: {
    inputFunc(event) {
      this.message = event.target.value
    }
  }
};

入力があれば、入力した値が data のmessageに反映される。そして{{ message }}{{ message.length }}にもリアクティブに反映されます。
これで先ほどの vanillaJS と同じことが実現できたわけです。
v-modelを使えばmethodsも不要だが、vanillaJS に寄せるため使用しなかった)

結局何が言いたいかというと、
今までは「この要素を作って」「このテキスト入れて」みたいな命令を出して、それを実現する UI は別の場所なので直感的でない。イメージしづらい。という状況だった。
Vue.js などの宣言的 UIというものは、予め「完成形の UI こんな感じ!」と宣言しておいて、動的な部分などは虫食い状態にしてあげている。という感じです。これで UI が直感的に分かりやすくなりました。

比較イメージ

まとめ

宣言的 UI とは、予め、完成形の UI を「完成形の UI こんな感じ!」と宣言的に書くこと。
そのおかげで、実現したい UI がイメージしやすいし、長ーいコードを書かなくて良くなります。

頭の中で分かったつもりでも言語化するのが難しかったです...。
もしも間違いや語弊を招く表現があれば教えていただけたら嬉しいです。
ありがとうございました!

参考

https://www.youtube.com/watch?v=7hVUV0fwKwg
https://zenn.dev/mizchi/books/0c55c230f5cc754c38b9
https://qiita.com/Yametaro/items/3c27305072464e1d6230

脚注
  1. アーカイブ → https://www.youtube.com/watch?v=x069r_jOZhk ↩︎

  2. 実際のスライド → https://speakerdeck.com/uhyo/2020nian-dai-shi-uji-shu-hadouxuan-bu?slide=13 ↩︎

GitHubで編集を提案

Discussion