📚

なぜVueを始めるべきか:文法

2024/09/13に公開

前置き

前回の記事ではデータバインディングについて
その中でもコンポーネントとコンポーネント間のデータバインディングについて詳細に話しました。

今回は実際プログラミングで使う文法について比較しようかと思っています。

Reactも同じですが、Vueも基本的にJavaScriptベースで作られたものなので
基本的なJavaScriptはVue内でも使えます。

ただ、各ライブラリー・フレームワークによってコーディングスタイルが違います。
特にフレームワークであるVueはレガシーJavaScriptよりはVueで提案している
文法を使うほうが良いでしょう。

比較対象について

今回比較対象は以下の通り
簡単なifforからライフサイクル関連関数まで話しようかと思っています。

基本的にReactはJavaScriptに近いほで
Vueの場合はVueで提供している文法があります。

  • リスト
    if, for, props渡しデータバインディング

各コードは以下の通りです。

コードとしては少し違うところがありますが、同じ機能になります。

例コードについて

フロントエンドで良く使うIF文の例は一部のUI(コンポーネント)を非活性にするところかと思います。
例えばボタンを押下したらポップアップ表示されたり、初期ページのデータを取得する前にローディング画面を表示する時に良く使います。

今回は簡単な例を用意しました。
テキストボックスがあり、入力すると三つのボックスに入力した内容が表示されます。
さらに3秒ごとに三つのボックスが表示・非表示されるコードになります。

全体なコードは以下のリンクで確認可能です。
https://codesandbox.io/p/sandbox/simple-react-223jyn?file=%2Fsrc%2FApp.js%3A25%2C1
https://codesandbox.io/p/devbox/simple-vue-9mmmn2?file=%2Fsrc%2Fcomponents%2FSimpleArea.vue%3A1%2C1-16%2C10

IF

まずはIF文です。

React: IF文

・・・
export default function App() {
 ・・・
 // 表示・非表示変数
  const [isShowBlock, setIsShowBlock] = useState(true);
  ・・・

  useEffect(() => {
    const intervalId = setInterval(() => {
   // 3秒ごとに表示・非表示変数の値を反転する
      setIsShowBlock((prev) => !prev);
    }, 3000);

    return () => clearInterval(intervalId);
  }, []);

  return (
    <div className="App">
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <!-- 表示・非表示変数がTrueなら表示、Falseなら非表示する -->
      {isShowBlock && (
        <div className="Wapper">
          {componentName.map((value, index) => (
            <SimpleArea input={input} name={value} key={index} />
          ))}
        </div>
      )}
    </div>
  );
}

ポイントになるコードは{isShowBlock &&と言うどころです。
Reactの場合、JavaScriptと同様です。
HTML(又JSX)内部ではIF文を使えないため、他の方法を使うしかないです。

一番簡潔な使い方は例見たいに**論理演算子(&&)**を使う方法です。

それ以外は条件 (三項) 演算子

<!-- 表示・非表示変数がTrueなら表示、Falseなら非表示する -->
      {isShowBlock ? (
        <div className="Wapper">
          {componentName.map((value, index) => (
            <SimpleArea input={input} name={value} key={index} />
          )) : null}
        </div>
      )}

この部分をそのまま関数化する方法があります。

function MyComponent({ isShowBlock }) {
  if (isShowBlock) {
    return (
        <div className="Wapper">
          {componentName.map((value, index) => (
            <SimpleArea input={input} name={value} key={index} />
          ))}
        </div>
    );
  } else {
    return null;
  }
}

つまり、Reactの場合JavaScriptと同様のため、
JavaScriptに慣れてないと上手く使うことが難しいです。

いろんな方法があるため、人によって使い方がバラバラになる可能性もあります。
なのでプロジェクト内で標準を決める必要があります。

Vue: IF文

App.vue
<template>
  <div>
    <input v-model="input" />
    <!-- 表示・非表示変数がTrueなら表示、Falseなら非表示する -->
    <div class="Wapper" v-if="isShowBlock">
      <SimpleArea v-for="(item, i) in componentName" :key="i" :input="input" :name="item" />
    </div>
  </div>
</template>

<script>
・・・
export default {
 ・・・
  data() {
    return {
   ・・・
      // 表示・非表示変数
      isShowBlock: true,
    };
  },
  ・・・
}
</script>

Vueの場合は、Vue内部でv-ifと言うキーワードが存在するため
タグ内に条件式をv-ifを入れるだけで終わりです。

For

React: For文

・・・
export default function App() {
 ・・・
  const componentName = ["component1", "component2", "component3"];
 ・・・
  return (
    <div className="App">
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      {isShowBlock && (
        <div className="Wapper">
          {componentName.map((value, index) => (
            <SimpleArea input={input} name={value} key={index} />
          ))}
        </div>
      )}
    </div>
  );
}

キーワードはcomponentNameと言う配列とmap()関数になります。
Reactの場合、IF文と同様な理由で一般的なfor文は使えません。
一番簡潔な使い方はMap関数を使う方法です。

Vue: For文

App.vue
<template>
  <div>
    <input v-model="input" />
    <div class="Wapper" v-if="isShowBlock">
      <SimpleArea v-for="(item, i) in componentName" :key="i" :input="input" :name="item" />
    </div>
  </div>
</template>

<script>
import SimpleArea from "./components/SimpleArea.vue";

export default {
    ・・・
}
</script>

キーワードは<SimpleArea>コンポーネント内のv-forになります。
Vueの場合はv-for内に数式を入力することで終わりです。

Props渡し, データバインディング

React : Props渡し

・・・
// inputとnameをpropsとして定義
const SimpleArea = ({ input, name }) => {
  return (
    <div className="SimplePanel">
      <div className="SimpleName">{name}</div>
      <div className="SimpleArea">{input}</div>
    </div>
  );
};

export default function App() {
  ・・・
  return (
    <div className="App">
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      {isShowBlock && (
        <div className="Wapper">
          {componentName.map((value, index) => (
            // input,nameをPropsとして設定
            <SimpleArea input={input} name={value} key={index} />
          ))}
        </div>
      )}
    </div>
  );
}

Reactの場合はPropsを受けているconst SimpleArea = ({ input, name })
<SimpleArea input={input} name={value} key={index} />部分がキーワードになります。

Propsを受ける側はパラメーターとして、渡す側は属性として設定します。

React : データバインディング

・・・
// inputとnameをpropsとして定義
const SimpleArea = ({ input, name }) => {
  return (
    <div className="SimplePanel">
      <div className="SimpleName">{name}</div>
      <div className="SimpleArea">{input}</div>
    </div>
  );
};

export default function App() {
  ・・・
  return (
    <div className="App">
      //単方向データバインディングのため、onChangeが必要
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      {isShowBlock && (
        <div className="Wapper">
          {componentName.map((value, index) => (
            // input,nameをPropsとして設定
            <SimpleArea input={input} name={value} key={index} />
          ))}
        </div>
      )}
    </div>
  );
}

以前の記事でも説明した通り、
Reactの場合は単方向データバインディングを採用しているので
<input value={input} onChange={(e) => setInput(e.target.value)} />
上のようにonChange内に追加でイベントトリガーを設定する必要があります。

Vue: Props渡し

SimpleArea.vue
<template>
    <div class="SimplePanel">
        <div class="SimpleName">{{ name }}</div>
        <div class="SimpleArea">{{ input }}</div>
    </div>
</template>

<script>
export default {
    name: 'SimpleArea',
  // inputとnameをpropsとして定義
    props: {
        name: String,
        input: String,
    }
}
</script>
App.vue
<template>
  <div>
  // v-modeキーワードで双方向データバインディング
    <input v-model="input" />
    <div class="Wapper" v-if="isShowBlock">
      // inputとnameをpropsとして設定
      <SimpleArea v-for="(item, i) in componentName" :key="i" :input="input" :name="item" />
    </div>
  </div>
</template>

<script>
・・・
export default {
  ・・・
  data() {
    return {
      input: "",
      componentName: ["component1", "component2", "component3"],
      isShowBlock: true,
    };
  },
 ・・・
}
</script>

VueもReactとほぼ同じです。

<SimpleArea v-for="(item, i) in componentName" :key="i" :input="input" :name="item" />

渡す側は頭に:キーワード付けてProps設定します。

<script>
export default {
    name: 'SimpleArea',
  // inputとnameをpropsとして定義
    props: {
        name: String,
        input: String,
    }
}
</script>

受ける側は<script>~</script>内部のprops内にProps名とタイプを定義します。

Vue: データバインディング

SimpleArea.vue
<template>
    <div class="SimplePanel">
        <div class="SimpleName">{{ name }}</div>
        <div class="SimpleArea">{{ input }}</div>
    </div>
</template>

<script>
export default {
    name: 'SimpleArea',
  // inputとnameをpropsとして定義
    props: {
        name: String,
        input: String,
    }
}
</script>
App.vue
<template>
  <div>
  // v-modeキーワードで双方向データバインディング
    <input v-model="input" />
    <div class="Wapper" v-if="isShowBlock">
      // inputとnameをpropsとして設定
      <SimpleArea v-for="(item, i) in componentName" :key="i" :input="input" :name="item" />
    </div>
  </div>
</template>

<script>
・・・
export default {
  ・・・
  data() {
    return {
      input: "",
      componentName: ["component1", "component2", "component3"],
      isShowBlock: true,
    };
  },
 ・・・
}
</script>

Vueの場合は双方向データバインディングを採用しているので
<input v-model="input" />
上のようにv-modelキーワードに変数を入れるだけど終わりです。

少し詳細に説明するとタグによって違いますが、
inputv-modelの場合、
変数を設定する:valueと入力された時にトリガーされる@inputが含めています。

そのため、
<input v-model="input" @input="event => input = event.target.value + 1"/>
上見たいにInputと同時に他の処理を入れたく、@inputを設定しまうと
内部的には@input処理が二つ存在することになるので、
v-modelを使う時には特に注意する必要があります。

その場合は、v-modelを使わず、:value@inputを使うほうが良いでしょう。

詳細な内容に関しては以下のリンクをご覧ください。
https://ja.vuejs.org/guide/essentials/forms

なぜVueを使うべきか:文法

ここまででVueとReactの文法について比較して見ました。

結論的にはReactの場合はJavaScriptの文法をそのまま使っているどころが多い面があり、
Vueの場合はVueだけの文法があります。

Vueの一番いいところはv-forv-ifと言うものがあり、
IFとFORをタグ内に使えるところです。

この二つだけでも
これだけども全体的なコードが綺麗になるので
Vueを使うメリットは十分あります。

あと、v-modelと言う双方向データバインディングも良い面かと思います。
もちろん注意は必要です。

つまりプロダクト早めに作りたい・ラニングコストが低いほうを大事するプロジェクトであれば
Vueのほうが良いかと思います。

もちろん、JavaScriptに慣れているメンバーが多いとか
柔軟性が必要であればReactになりますね。
あと、全世界的にVueよりはReactのほうを使っているので
Reactの情報が多い面もReactのメリットになります。

次の記事では今までの記事をまとめて結論を出してみましょう。

参考

https://ja.vuejs.org/guide/essentials/template-syntax

GitHubで編集を提案

Discussion