Reactが趣味の未経験者によるVue3備忘録

筆者はもともとReact(TypeScript)+Railsについて（趣味とスキルアップを兼ねて）1年半ほど学習しておりましたが、より地方の求人の実情に沿ったVue(TypeScript)+Laravelというスキルスタックへと、ごく最近になってコンバートした人間です。
Vueの設計思想についても全くの不案内なので、完全になっちゃいねえ発言を連発するかと思いますが、どうか生暖かく見守ったりマサカリを投げて頂ければ幸いです。
なお今回の記事ではTSに関する言及はありません。

#ステートの管理
Vue3より各コンポーネントの状態を関数っぽく管理する「Composition API」なるシステムが導入された。
コンセプトを聞いたときに何となくReact hooksを連想したのだが、触ってみると**本当にReact hooksみたい**だった。観測範囲のVueユーザーからは「とっつきづらい」と不評のシステムだが、Reactユーザーから見たVueの敷居は大きく下がったと言っていい。

```javascript:App.vue
<template>
  <h1>{{number}}</h1>
//{{}}で囲むと変数を使える
  <input v-model="diff" type="number">
//キー⇔インプットのインタラクションはv-modelで実現

  <Counter
  @increment="addNumber(true)"
  @decrement="addNumber(false)"
  />
//@eventName=function(arg)で子コンポーネント内のイベントに
//反応して関数を実行できる
</template>

<script>
import {ref} from "vue"
import Counter from "@/components/Counter"
//importはexport defaultの外で済ませる
export default {
  name: 'App',
  components:{Counter},
  setup(){
//各stateならびにstateを変化させる関数を設定
    const number = ref(1);
    const diff = ref(1);
//stateはref()で作る
//まとめて複数のstateを作る場合はreactive()内にオブジェクトを作成
    const addNumber =(isPlus)=>{
      if(isPlus){
        number.value += Number(diff.value);
//ReactのuseState()と違い、stateの値を直接変更可能
//ただし値はstate.valueに収納されるので要注意
      }else{
        number.value -= diff.value; 
      }
    }
    return{number,addNumber,diff};
//ここでreturnしたオブジェクトがtemplate内で使える
  }
}
</script>
```
```javascript:Counter.vue
<template>
  <div>
    <button @click="onIncrement">+</button>
    <button @click="onDecrement">-</button>
  </div>
</template>
<script lang="ts">
export default {
  name:"Counter",
  emits:["increment","decrement"],
//emits:[]でカスタムイベントを宣言
  setup(props,context){
//setup()の第二引数であるcontextからemitが取り出せる
    const onIncrement =()=>{
      context.emit("increment");
//emitsで宣言したincrementイベントをエミット
    }
    const onDecrement =()=>{
      context.emit("decrement");
    }
    return{
      onIncrement,
      onDecrement
    };
  }
}
</script>
```
Reactとの比較で気になった点としては、

- ``v-model``を使えば、一行でinputに入力した値とステートを直結できるのはかなりいい感じ。ReactのonChangeでイベントを拾う→e.target.valueで値を取り出してステートを変える→inputのvalueをstateに指定する　というやり方よりも大分良いのではないか。
- 子コンポーネントでボタンをクリックして親コンポーネントの値を変える時イベント駆動型のアプローチを取るのは面白いと思った。思ったのだが、イベントをエミットするための手続きがいくらなんでも煩瑣すぎやしないか。

#ド定番　Todoリストを作る
変数⇔テンプレート内の各要素のインタラクションをもう少し詳しく見るため、定番のTodoリストを作る。
どうやら、

- 変数に合わせて動的に要素を変えるには``:``を付ける
- イベントリスナを要素に付与するには``@``を付ける
- input⇔キーのインタラクションは``v-model``を使う

というルールのようだ。

```javascript:App.vue
<template lang="">
  <div>
    <ul>
      <li v-for="task in taskList" :key="task.id">
//v-forを使って配列に沿って要素を作れる。
//reactだとJSX内でのmapみたいなもん。
      <span :class="{done:task.done}">
//classにコロンを付ければ動的に指定できる。
//task.doneがtrueならdoneクラスを追加。
        {{task.name}}
      </span>
      <span @click="toggleDone(task.id)">✒</span>
      </li>
    </ul>
    <form action="submit" @submit.prevent="onSubmit">
//Reactで言うe.preventDefault()は
//Vueではtemplate内のイベントリスナ修飾子として実装する
    <input v-model="newTask" type="text">
    <button>追加</button>
    </form>
  </div>
</template>
<script>
import {ref} from "vue";
import { uuid } from 'vue-uuid';
export default {
  name:"App",
  setup(){
//以下のロジックはReact hooksで
    const taskList = ref([]);
    const newTask = ref("");
    const toggleDone =(id)=>{
      const taskToChange = taskList.value.find(task=>{
        return task.id === id;
      });
      taskToChange.done = !taskToChange.done;
    }
    const onSubmit =()=>{
      taskList.value.push({
        id:uuid.v1(),
        name:newTask.value,
        done:false
        });
      newTask.value = "";
    }
    return{taskList,newTask,onSubmit,toggleDone};
  }
}
</script>
<style>
  .done { 
    text-decoration: line-through; 
    }
</style>
```