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

4 min read読了の目安(約4000字

経緯

『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要素を取得すr

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 ↩︎