なぜVueを始めるべきか:データバインディング(DataBinding)
概要
以前の記事でReactとVueをアーキテクチャーについて話して見ました。
結論的にはデータバインディング(DataBinding)と言うデータ反映方法が違います。
つまり実際ユーザーに表示されるViewと実際データを管理しているModel間でどうやって、
どのようにデータを反映をするかと言う方法の違いになります。
Reactは単方向データバインディング(One-way Data Binding)を採用
Vueは双方向データバインディング(Two-way Data Binding)採用しています。
今回はこの二つのバインディングについて詳しく話したいと思っています。
以前の記事は以下のURLでご覧ください。
まずは前回の記事の振り返りを含めて
単方向データバインディング(One-way Data Binding)と
双方向データバインディング(Two-way Data Binding)について話して見ましょう。
振り返り:単方向データバインディングと双方向データバインディング
まずは前回の記事の内容を少し振り返りしたいと思います。

上の画像は一般的なMVC又MVC派生パータン内でのModelとView内のデータバインディングの方法、
つまり単方向データバインディング(One-way Data Binding)と双方向データバインディング(Two-way Data Binding)を表示しています。
結論的には二つの相違点はViewからModel内のデータ反映方法にありますが、
単方向の場合は開発者が直接明示する必要があり
双方向の場合はシステム又フレームワークで自動でModelに反映されます。
バインディング:Model-View観点とコンポーネン観点
前回記事で話したものはModelとView間のデータバインディングののみ話しましたが
実はコンポーネンの立場でも考える必要があります。
Reactも同じですが、Vueもコンポーネントベースアーキテクチャーを採用しているためです。
そのため、親コンポーネントと子コンポーネント間でもデータバインディングが必要になります。
今回はアーキテクチャーについて話するよりは例で説明すようかと思っています
バインディング(コンポーネン観点)の例:時計アプリケーション
例として時計のアプリがあると仮定しましょう。
このアプリは以下のイメージ通りです。

上段にはアナログ時計を下段にはデジタルの時計を表示したいです。

これをコンポーネント観点で見ると上の画像通り
親コンポーネントと子コンポーネントで分離できます。
この場合どうやってデータをコンポーネントに渡すほうが良いでしょう。

- 左のように、各子コンポーネントでデータを取得する
- 右のように、親コンポーネントからデータを受けてそのデータを子コンポーネントへ展開
もちろん、外部からデータをもらいう回数も一回だし、各コンポーネントの同期化も考えると
2番目の方法が一番良いでしょう。
そのため、親・子コンポーネントのデータバインディングも考える必要があります。
つまりView内の各View間にもデータバインディングが必要って言う話になります。
ただ、ここで問題が発生します。
バインディング(コンポーネン観点)問題:Props Drilling
こちらからがこの記事のメインになります。
この問題はコンポーネントベースアーキテクチャー(Component-Based Architure)を採用する場合、
現れる代表的な問題になります。
設計プロセスよりは実装の段階で現れる問題です。
今の例として出している時計アプリは
そんなに複雑な構成ではないので、
このProps Drillingと言う問題は発生しないですが、
一般的に良く現れる問題になります。
実際世界で使われているアプリは簡単ではないですからね。
Props Drillingとは?
<Wapper>
<Analog 時間 />
<Digital 時間 />
</Wapper>
上の例である時計アプリの構成の一番上のコンポーネントは上のようになりますでしょう。
時間と言うプロパティを各子コンポーネントに展開しています。
このパータンの場合はあまり感じれないかもしれません。
この機能が拡張され<Analog>コンポーネント内に色んな機能がある場合はどうでしょう。
<Wapper>
<Time 時間 />
<Date 時間 />
</Wapper>
<Analog>コンポーネント内の<Time>,<Date>でもこの時間を使う場合はどうでしょう。
この<Time>内でも時間が必要場合を同じく時間を設定する必要があります。
この時間が無くなった場合、全コンポーネントを修正しなければならないし
コンポーネントを追加した時にもこのプロパティを作成しなければならないので
いろいろめんどくさいですよね。
別の話ですが、この問題を見るとJavaScriptで非同期処理する時に現れる
CallBack地獄(Callback Hell)の問題が思い出しましね。
JavasciprtではこれをPromiseオブジェクトをベースでasyncとwaitで解決しましたよね。
もちろん、これのProps Drillingを解決方法はあります。
Props Drilling解決:React
Reactの場合はContext APIがあるでしょう。
useContextと言う関数を使います。
import { createContext, useContext } from 'react';
const ThemeContext = createContext(null); // context宣言
export default function MyApp() {
return (
<ThemeContext.Provider value="dark"> // 定義したcontextで囲む
<Form />
<Button />
<Component1 />
<Component2 />
</ThemeContext.Provider>
)
}
定義したThemeContextにコンポーネントを囲むとdarkを
<Form />,<Button />,<Component1 />,<Component2 />でも使えます。
さらに未来に使えるかもしれないコンポーネントも同じでしょう。
function Button({ children }) {
const theme = useContext(ThemeContext); // 変数themeには文字列'dark'が格納される
const className = 'button-' + theme; // 変数classNameには'button-dark'格納される
return (
<button className={className}>
{children}
</button>
);
}
定義したThemeContextの値を取得するためにはuseContextを使います。
感想的には少し複雑に見えますね。
詳しい内容は以下の公式ドキュメントご覧ください。
Props Drilling解決:Vue
VueではProvide/Injectがあります。

使い方は簡単です。
<script setup>
import { provide } from 'vue'
provide(/* key */ 'message', /* value */ 'hello!')
</script>
provide関数内にキー,値セットで格納して
<script setup>
import { inject } from 'vue'
const message = inject('message')
</script>
inject関数でキーを入れて、値を取得することができます。
provideで値を格納、injectで値を取得するだけなので
ReactよりはVueのほうが簡単な気がしますね。
詳しい内容は以下の公式ドキュメントご覧ください。
なぜVueを使うべきか
結論的にはこのProps Drillingの解決方法に対しては
Reactの場合はVueのほうが使いしやすいでしょう。
Reactの場合は以下の手順が必要です。
- React
- Contextインスタンス作成
- Contextインスタンスを呼び出す
- Contextでコンポーネントに囲む
- useContextで値を取得
Vueの場合は以下の手順になります。
- Vue
- provideで値を格納
- injectで値を取得
以前の記事でも同じ話をしましたが、
初心者向けでもVueのほうが良さそうと感じれます。
以上でデータバインディングの話は終わりたいと思っています。
次の記事ではアーキテクチャーとか理論的な話はここまでにして
ReactとVueの文法を比較したいと思います。
参考
Discussion