📢 この記事は gemini-2.5-flash によって翻訳されました
プロジェクト作成
Node.js 16.0以上が必要だよ。以下のコマンドを実行してみて。
このコマンドを実行すると、create-vueがインストールされて実行されるんだ。
setup
実行タイミング
beforeCreate()よりも早く実行されるから、thisは使えないんだ。
1
2
3
4
5
6
7
8
9
10
| <script>
export default{
setup(){
console.log('setup', this)
},
beforeCreate(){
console.log('beforeCreate')
}
}
</script>
|
実行すると、まず「setup undefined」が出力されて、それから「beforeCreate」が表示されるよ。
データ呼び出し
<template>でsetup()関数内で定義したデータや関数を使いたいなら、returnしないといけないんだ。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| <script>
export default{
setup(){
// data
const msg = 'hello vue3'
// function
const logMsg = () => {
console.log(msg)
}
// return
return{
msg,
logMsg
}
}
}
</script>
|
returnしてからじゃないと、<template>で使えないからね。
1
2
3
4
| <template>
<div>{{ msg }}</div>
<button @click="logMsg">button</button>
</template>
|
シンタックスシュガー
毎回returnするのは正直面倒だよね。実は、<script>タグにsetupって付ければ、自動でreturnしてくれるようになるんだ。さっきの例だと、こう書けるようになるよ。
1
2
3
4
5
6
| <script setup>
const msg = 'hello vue3'
const logMsg = () => {
console.log(msg)
}
</script>
|
もちろん、実際はreturnされてるんだけど、自分で書かなくてよくなるってことだね。
リアクティブなデータ
reactive
reactive()関数はオブジェクト型のデータを受け取って、リアクティブなオブジェクトを返すんだ。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| <script setup>
import { reactive } from 'vue'
const state = reactive({
count: 100
})
const addCount = () => {
state.count++
}
</script>
<template>
<div>
<div>{{ state.count }}</div>
<button @click="addCount">+1</button>
</div>
</template>
|
ref
ref()は、プリミティブ型でも複雑な型でも受け取って、リアクティブなオブジェクトを返すよ。本質的には、渡されたデータの上にオブジェクトでラッピングして、より複雑な型にしてるんだ。これも実はreactive()を使ってリアクティブを実現してるんだよね。
だから、<script>でデータにアクセスするときは.valueを使う必要があるんだ。でも、<template>でアクセスするときは、変数名をそのまま使えばOKだよ。さっきの例をref()で書き直すとこうなるよ。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <script setup>
import { ref } from 'vue'
const c = ref(0)
const addC = () => {
c.value++
}
</script>
<template>
<div>
<div>{{ c }}</div>
<button @click="addC">+1</button>
</div>
</template>
|
実際の開発ではref()だけを使うと、より柔軟で統一感のあるコードになることが多いよ。
computed
算出プロパティのcomputed()はVue2と似てるけど、好きなときに呼び出せる関数になったんだ。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <script setup>
import { computed, ref } from 'vue'
const list = ref([1, 2, 3, 4, 5, 6, 7, 8])
const computedList = computed(() => {
return list.value.filter(item => item > 2)
})
</script>
<template>
<div>{{ list }}</div>
<div>{{ computedList }}</div>
</template>
|
こうやって作ったプロパティは読み取り専用で、書き込みはできないんだ。もし書き込みも必要なら、get()とset()を明示的に宣言する必要があるよ。以下は公式のサンプルから引用したんだ。
1
2
3
4
5
6
7
8
9
10
11
12
| <script>
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: (val) => {
count.value = val - 1
}
})
plusOne.value = 1
console.log(count.value) // 0
</script>
|
引用元:
https://cn.vuejs.org/api/reactivity-core.html#computed
watch
watch()関数も同じように、1つまたは複数のデータの変更を監視して、データが変更されたときにコールバック関数を実行するんだ。ただ、immediateとdeepっていう2つの追加パラメータが増えたよ。
1
2
3
| watch(count, (newValue, oldValue) => {
console.log('count changed', oldValue, newValue)
})
|
1
2
3
| watch([count, name], ([newCount, newName], [oldCount. oldName]) => {
console.log('count or name has changed', [newCount, newName], [oldCount. oldName])
})
|
サンプルだよ。ここでは簡略化したPugを使ってるけど、これもけっこう分かりやすいはずだよ。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| <script setup>
import { ref, watch } from 'vue'
const count = ref(0)
const name = ref('John')
const addCount = () => count.value++
const changeName = () => name.value = 'Mike'
// 単一データの変更を監視
watch(count, (newValue, oldValue) =>{
console.log('count changed', oldValue, newValue)
})
// 複数データの変更を監視
watch([count, name], (newArr, oldArr) => {
console.log('count or name changed', oldArr, newArr)
})
</script>
<template lang="pug">
div count: {{ count }}
button(@click="addCount") +1
div name: {{ name }}
button(@click="changeName") change name
</template>
|
immediateはすぐに実行されるって意味で、ページに入ったらすぐに1回実行されるんだ。このときoldValueはundefinedになるよ。
1
2
3
4
5
| watch(count, (newValue, oldValue) =>{
console.log('count changed', oldValue, newValue)
}, {
immediate: true
})
|
deep
deepはディープウォッチャーだよ。デフォルトのwatchはシャローウォッチャーだから、複雑な型の変更は監視できないんだ。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| <script setup>
import { ref, watch } from 'vue'
const userInfo = ref({
name: 'John',
age: 18
})
const changeUserInfo = () => {
userInfo.value.age++
}
watch(userInfo, (newValue) => {
console.log('userInfo changed', newValue)
}, {
deep: true
})
</script>
<template lang="pug">
div {{ userInfo }}
button(@click="changeUserInfo") change userInfo
</template>
|
複雑な型の単一プロパティ監視
deepを使うと、複雑な型のすべてのプロパティを監視することになるんだ。つまり、どのプロパティでも変更があれば関数が実行されるってこと。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| <script setup>
import { ref, watch } from 'vue'
const userInfo = ref({
name: 'John',
age: 18
})
const changeAge = () => {
userInfo.value.age++
}
const changeName = () => {
userInfo.value.name = 'Mike'
}
watch(() => userInfo.value.age, (newValue, oldValue) => {
console.log('age changed', oldValue, newValue)
})
</script>
<template lang="pug">
div {{ userInfo }}
button(@click="changeAge") change age
button(@click="changeName") change name
</template>
|
こうすると、ageが変更されたときにだけトリガーされるし、戻り値もageの値になるんだ。
ライフサイクルフック
Vue3のライフサイクル比較
| Option API | Composition API |
|---|
| beforeCreate/created | setup |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeUnmount | onBeforeUnmount |
| unmounted | onUnmounted |
Composition APIでの違いは、関数呼び出しになって、複数回呼び出せるようになったってことだよ。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| <script setup>
import { onMounted } from 'vue';
// Composition APIでのbeforeCreateとcreatedは直接ここに書くよ
const getList = () => {
console.log('バックエンドからデータを取得')
}
// 実行、ページに入ったらすぐにリクエスト
getList()
// ライフサイクルフックは複数回呼び出せて、順番に実行されるよ
onMounted(() => {
console.log('ロジック1')
})
onMounted(() => {
console.log('ロジック2')
})
</script>
|