mt_coff's log

メモとか雑に

ReactからVueへ移行して苦労したこと & Vueで今年知ったこと

これは Aizu Advent Calendar 2019 の 6 日目の記事です。(大遅刻してすみません 🙇‍♂️) 5 日目は @4rotsugd さんでC++ SSE/AVX 入門の記録、 6 日目は @acomagu さんのmakepkg-template で PKGBUILD の管理をちょっとだけ楽にするです。

去年も遅れてましたね...
(技術的に浅い話だけど許して)

React から Vue

なぜ React から Vue へ

普段私は Vue を使った Web アプリケーションを作成したりしなかったりしています。 某プロジェクトで私はとあるアプリケーションを作成することになったのですが、完全に個人開発だったのと静的ファイルを配信するだけだったため、普段とは違う React で実装を勧めました。

~某日~
私 「7 割ぐらい実装終わったぞ!(余裕の表情)」
天の声 「他で Vue 使ってるから Vue 使ってください」
私 「()」

こうして React から Vue への移行作業が始まったのです...

簡単にですが一瞬でも移行で詰まったことを少しだけ書いていきます。

子要素の定義

React では子コンポーネントを以下のようにすることで<MyComponent><div>hoge</div></MyComponent> といったことができます。

const MyComponent = ({ children }) => {
  return <div>{children}</div>;
};

何もおかしなことはしていませんね。特に難しくもないです。基本。

<template>
  <div>
    <slot />
  </div>
</template>
<script>
  export default {
    name: "MyComponent"
  };
</script>

とすることで同じことができます。
React では Props を利用して、Vue では Slot を利用しています。
移行の際に <slot /> を思い出せなかった記憶があります...。

イベント

TypeScript を使って Vue を書いていて以下のようなコードを書いたことがある方いると思います。

methods: {
  handleInput(event: Event) {
    if (event.target instanceof HTMLInputElment) {
      console.log(event.target.value);
    };
    // as 使っちゃう ver
    console.log(event.target as HTMLInputElment).value);
  }
}

React だとこうなります。

const handleChange = (event: React.FormEvent<HTMLInputElement>) => {
  console.log(event.target.value);
};

大きな違いではありませんが、React から Vue へ移行した際に便利な型生えてて欲しかった気持ちがあった気がします()

値の監視

Vue では watch を利用して値が変更されたら実行される関数を定義できます。

data() {
  hoge: false
},
watch: {
  hoge(newHoge) {
    console.log(newHoge)
  }
}

React では useEffect を利用して似たことができます。

const [hoge, setHoge] = useState(false);

useEffect(() => {
  console.log(hoge);
}, [hoge]);

// hogeが変更されるような処理
...

React から Vue へ移行した際に useEffect を利用したコードをどうするかといったことは悩みませんでした。 ただ、本質的には watch, useEffect は別物なので同じことができるだけで混同しないように気をつけたいところです。

今年始めて知った/使った Vue の API など

Composition API

Vue 3.x から導入される予定の API で以下のようにすれば 今でも利用できます。

$ npm install @vue/composition-api

ここでは解説しないので気になる方はこちら を読んでください。
Vue でおなじみの this.xxx といった書き方をせず setup 関数内に変数やイベント、ライフサイクルフックなどを書いていく感じで props に関しても TypeScript を利用する際に typeinterface を利用した型定義をしっかりできるのは便利。

v-slot

私が知っていたのは slotslot-scopeでした。これらが非推奨になり、統合されたのが v-slotです。
以下のように利用します。

<!-- 定義側 -->
<template>
  <div>
    <div>
      <slot />
    </div>
    <div>
      <slot name="piyo" />
    </div>
  </div>
</template>

<!-- 利用する側 --->
<template>
  <my-layout>
    <div>something</div>
    <template v-slot:piyo>
      <div>piyo</div>
    </template>
  </my-layout>
</template>

slotnameは動的に割り当てたりすることも可能ですが、スペースや記号が入っていると利用する側で素直に v-slot:xxx と書けなくなるので個人的にはできれば避けたいです。
v-slot:[something]といった書き方もできます(something は data)。 v-for などを利用して子のスロットの name に値を渡すなどする場合やスペース、記号が混入する場合などはこちらを利用しましょう。

model

v-model がどの値をプロパティとして持ち、どのイベントを利用するか変更できます。
通常は valueinputイベントの組み合わせですが、change イベントを利用したかったりする場合などに利用します。

model: {
  prop: "value",
  event: "change"
}

ドキュメントの API の部分を探さないと出てこない(多分)のでchagne イベントで呼び出した関数の中で inputを emit するか input を emit する関数を呼んでいた人もいるはずです。(いてくれ...)