Open13

Vue3 & Nuxt3 やってみる

ikeponikepon

目的

  • お仕事で Vue を使っているので基本的な構文などを理解して、基礎的なコードなら書ける・読めるようになる
  • 将来的に応用が効くような基礎部分を固める
ikeponikepon

Vue3 のチュートリアル

まず、以下をやってみる

Step1

  • tutorial が終わったら Guide を読めって言っている
  • Options API と Composition API の 2 つの API styles が存在する
    • https://vuejs.org/guide/introduction.html#api-styles
      • Options API
        • data , methods , mounted といったオプションオブジェクトを使ってコンポーネントのロジックを定義する
        • オプションで定義されたプロパティは functions の中で this を使って公開される
      • Composition API
        • インポートされた API functions を使ってコンポーネントのロジックを定義する
        • SFC では <script setup> で使用される
        • setup 属性はコンパイル時の変換のヒントになっている
  • SFC mode と HTML mode がある
    • SFC(Single File Component)
    • Vue を使ってる開発者のほとんどがこれらしい
      • .vue ファイルの中に HTML, CSS, JavaScriot が全部入ってる
  • tutorial上で切り替えられる
    • ★ ひとまず、Options API, SFC で行く

Step2

  • declarative rendering: Vue の core feature
    • 宣言的レンダリング(?)
      • HTMLを拡張したテンプレートシンタックス
      • JS の state に合わせてHTMLが自動的に更新される
      • リアクティブな state はコンポーネントに保持される
        • リアクティブ
          • ★ 状態の変化を自動的に伝播する仕組みのことだと思う
      • data を使ってリアクティブな state を宣言できる
        • data は オブジェクトを返す関数
        • data 内で定義したオブジェクトはHTML内の {{ }} で表示できる
          • ★ mustaches syntax というらしい
          • この中は任意の JS 表現を使える
            • ★ これ、内容によるけど HTML 内でやるのか、data 内でやるのかは考える必要がありそう
ikeponikepon

Step3

  • v-bind
    • 属性をダイナミックな値に紐付ける
  • v- から始まるものは Vueのテンプレートシンタックス、ディレクティブというっぽい
  • data のプロパティを入れたりできる
  • titleClass って CSS の class があるとして、 v-bind:class="titleClass で紐付けれる
    • :class="titleClass" って省略形もあるっぽい

Step4

  • v-on で DOM イベントを listen できる
    • v-on:click="increment"
      • @click="increment" とも書ける
    • click したときの increment は methods 内で定義する
ikeponikepon

Step5

  • v-bindv-on で双方向バインディングができる
  • v-model は上記のシンタックスシュガー
    • input の value に自動的に紐付ける
    • checkbox とか他の input にも紐付けられる
    • ★ これをしない場合は更新メソッドを methods に定義して input に v-on で紐付けないといけない
      • v-model をすると勝手に紐付いて更新してくれる
      • Formデータを送信するときに自動で紐付け・反映してくれるから、そういうときに使うのかなと想像している
ikeponikepon

Step6

  • v-if は条件分岐
  • v-else-if , v-else がある

Step7

  • v-for
    • リスト表示

Step8

  • Computed Property
    • 他のプロパティから計算される state をリアクティブに反映したプロパティを宣言できる
    • ★ data に定義した値を処理して要素を絞り込むとかを定義するものだと思う
  • checkbox に v-model を設定すると boolean をいい感じで紐付けてくれる
ikeponikepon

Step9

  • ref 属性
    • mounted の中で this.$refs で参照できる
      • ライフサイクルフックと呼ばれるもので、コンポーネントのライフサイクルの特定のタイミングで呼び出されるコールバックを登録することができる
      • 他にもcreatedやupdatedなどのフックがある
      • Lifecycle Diagram
    • Template Refs
      • ★ なんかいろいろあるけどあとで読んでおく

Step10

  • Watchers
    • data で設定した property を監視する
    • 変更があったらそれを元に処理できる
    • count ってプロパティがあった場合、 count(newCount) で更新があった値を取得できる
    • ★ 例に mounted があるけど、watchしてるときに this.fetchData() してるんで二重に動いてる気がする
      • そんなことないな、mounted はレンダリングされた直後に一回だけ動く
      • その後で変更があったら watch が動いてる感じ
ikeponikepon

Step11

  • Components
    • 入れ子にコンポーネントを使うことができる
    • ★ コンポーネントにスタイルとかいろいろ閉じ込められるからいい感じで使い回せる様になるんだと思う

Step12

  • Props
    • 親から子へ、props を通して値を渡せる
    • props: { msg: String } みたいな感じで型を定義できるっぽい
    • this.msg みたいな感じで使えるんだと思う
    • ★ 例では :msg="greeting" って binding してる
      • これをすると data と紐づくっぽい
      • msg="greeting" みたいに : にすると binding しないので単に "greeting" って文字が表示される

Step13

  • Emits
    • 子から親にイベントを送る
    • 子に emits: ['response'] を定義
    • 子に this.$emit('response', 'hellow from child')
      • 最初の引数が emits で定義したものに対応してる
      • それ以降の引数が親の event listener に送られる
      • 親は v-on(@) で受ける
        • @response="(msg) => childMsg = msg"
ikeponikepon

Step14

  • Slots
    • slots を通して親から子にtemplate fragments を渡せる
      • template fragments: テンプレートの破片、任意のHTMLだと思う
    • 子は <slot /> で受け取ったものを出力できる
      • <slot>Fallback content</slot> みたいに中に入れると親から slot が送ってこなかった場合に表示するものをおける
ikeponikepon

Quick Start

  • https://vuejs.org/guide/quick-start.html
    • この例では Composition API を使っている
  • ★ index.html がエントリーポイントっていうのか?これが軸になってる
    • ここで main.js を読んでる
      • createApp(App).mount('#app') で index の #app を mount してアプリを表示してる
      • この App が RootComponent になってる
  • 以下みたいに複数の Vue app を同じページで動かせる
const app1 = createApp({
  /* ... */
})
app1.mount('#container-1')

const app2 = createApp({
  /* ... */
})
app2.mount('#container-2')
  • nextTick()

  • computed と methods の違い

    • computed の結果はキャッシュされるので再レンダリングされるときは同じ値になる
    • methods はキャッシュされないので再レンダリングの際は再計算される

Instead of a computed property, we can define the same function as a method. For the end result, the two approaches are indeed exactly the same. However, the difference is that computed properties are cached based on their reactive dependencies. A computed property will only re-evaluate when some of its reactive dependencies have changed. This means as long as author.books has not changed, multiple access to publishedBooksMessage will immediately return the previously computed result without having to run the getter function again.

This also means the following computed property will never update, because Date.now() is not a reactive dependency:

computed: {
  now() {
    return Date.now()
  }
}

In comparison, a method invocation will always run the function whenever a re-render happens.

  • v-show と v-if
    • 一般的に、v-ifはトグルコストが高く、v-showは初期レンダリングコストが高いと言われています。そのため、頻繁に何かを切り替える必要がある場合はv-showを、実行時に条件が変化する可能性が低い場合はv-ifを選択します。
    • ★ v-show は display:none になるので表示の切り替えコストは少ない
      • v-if は html要素ごと消すのでレンダリングコストが掛かるってことだと思う
ikeponikepon
  • Mutation Methods

    • これらが使われるとVueは変更検知する
      • push()
      • pop()
      • shift()
      • unshift()
      • splice()
      • sort()
      • reverse()
  • Non-mutating Methods

    • 新しい配列が生成されて返される
      • filter()
      • concat()
      • slice()
      • ★ この場合もVueがいい感じに扱ってくれて既存レンダリングされたものを使って処理してくれるっぽい
  • computed プロパティでの注意

    • reverse() と sort() には注意が必要
    • この2つのメソッドは、元の配列を変化させるので、計算されたゲッターでは避けるべき
    • これらのメソッドを呼び出す前に、元の配列のコピーを作成する
- return numbers.reverse()
+ return [...numbers].reverse()
ikeponikepon
  • inline handler で引数とイベントを取りたいとき
    • $event で取れる
<!-- using $event special variable -->
<button @click="warn('Form cannot be submitted yet.', $event)">
  Submit
</button>

<!-- using inline arrow function -->
<button @click="(event) => warn('Form cannot be submitted yet.', event)">
  Submit
</button>

methods: {
  warn(message, event) {
    // now we have access to the native event
    if (event) {
      event.preventDefault()
    }
    alert(message)
  }
}
  • Event Modifiers

    • ★ prevent はなんとなく分かるけど、それ以外は動かして確認するのが良さそう
      • 初見ではちょっと理解できない...
  • Key Modifiers

    • キーボード操作イベントを捕まえるやつ
    • ★ 例とかみるといろいろあるので、必要に合わせて使っていく
  • Form Input Bindings

    • ★ 例がたくさんあるので Form 処理するときは参考にすると良さそう
  • Lifecycle Hooks

    • ★ 以下の画像を頭に入れておけば大丈夫そう
  • Watchers

    • プロパティの変更を検知する
      • ★ data とかで定義したプロパティをメソッド名にすればあとは勝手に監視してくれるんだと思う
    • nested されたプロパティの変更は監視しない
      • deep watcher を使う必要がある( deep: true を設定すれば監視してくれる?)
        • 大きいobjectだったらパフォーマンスに影響があるかも
    • watch はデフォルトで lazy
      • すぐに見たい場合は immediate: true を設定すればいい
    • デフォルトでは、ユーザーが作成したwatcher callback は、Vueのコンポーネントが更新される前に呼び出される
      • ウォッチャーコールバックの内部でDOMにアクセスしようとすると、DOMはVueが何らかの更新を適用する前の状態になる
      • Vueが更新した後にウォッチャーコールバックでDOMにアクセスしたい場合は、flush: 'post' オプションを指定する必要がある
ikeponikepon
  • Template Refs

    • ★ HTML DOMを直接参照するんだと思う
      • 例がいろいろあがってるのであとでちゃんと見る
  • Components Basics

    • ★ 例がいろいろあがってるのであとでちゃんと見る

ここから先は Component の詳細になっていくので一旦保留
Nuxt に移る

ikeponikepon

Nuxt3

  • pages ディレクトリ
    • ページの URL に対応するファイル名.vue を作ると自動的にルーティングされる
  • components ディレクトリ
    • コンポーネントを入れるディレクトリで、自動的に import される
      • pages のファイルで import とか書かなくても読み込んでくれるので使えるっぽい
  • App.vue
    • Nuxt の一番のルートコンポーネント
      • `NuxtPage タグを入れると pages ディレクトリの内容が反映されてルーティングが効くっぽい