概要
以下の動画の文字起こし&理解の整理
https://www.youtube.com/watch?v=XIpQLdcqawc
Composition APIとは
柔軟にコンポーネントをかける
なぜ使うのか
- 保守性の向上
- 再利用性の向上
Vue2 -> Vue3
Vue2で書かれたコード
// src/components/CounterMouse.vue
<template>
<div @mousemove="updateMouse">
<div>
Count is {{ count }}, count * {{ times }} is {{ multiplicationResult }}
<button @click="increment">
+
</button>
</div>
<div>Mouse is at {{ mousePosition.x }}, {{ mousePosition.y }}</div>
</div>
</template>
<script>
export default {
props: {
times: {
type: Number,
default: 2
}
},
data() {
return {
mousePosition: {
x: 0,
y: 0
},
count: 0
}
},
computed: {
multiplicationResult() {
return this.count * this.times;
}
},
watch: {
count() {
setTimeout(() => {
alert('3 seconds have passed since the value changed');
}, 3000);
}
},
methods: {
increment() {
this.count += 1;
},
updateMouse(event) {
this.mousePosition.x = event.clientX
this.mousePosition.y = event.clientY
},
}
}
</script>
Vue3で書き換えたコード
// src/components/CounterMouse.vue
<template>
<div @mousemove="updateMouse">
<div>
<!-- you can omit ".value" to get the value in template -->
Count is {{ count }}, count * {{ times }} is {{ multiplicationResult }}
<button @click="increment">
+
</template>
<script>
// "reactive" can be passed only object as argument
// "ref" can be passed not only object such as Number, String, and so on
// you should access the value with ".value" if you use "ref"
import { reactive, ref, computed, watch } from '@vue/composition-api';
export default {
props: {
times: {
type: Number,
default: 2
}
},
// "setup" is executed before "beforeCreate"
// That's why "this" cannot be used
// "setup" has first argument of props
setup(props) {
// data
const mousePosition = reactive({
x: 0,
y: 0
});
let count = ref(0);
// methods
const increment = () => {
count.value += 1;
};
const updateMouse = (event) => {
mousePosition.x = event.clientX
mousePosition.y = event.clientY
};
// computed
const multiplicationResult = computed(() => {
return count.value * props.times;
});
// watcher
watch(count, () => {
setTimeout(() => {
alert('3 seconds have passed since the value changed');
}, 3000)
})
return {
mousePosition,
count,
increment,
updateMouse,
multiplicationResult
}
},
}
</script>
補足
reactiveとは
仮に以下のようなコードがあった時、依存関係のあるものが変更された時に更新される状態をreactiveと呼ぶ
つまり、xが変化すれば、aの値も変化する状態
let x = 1;
let a = x + 3;
x = 3;
a is 4? or 6?
保守性をあげる(見やすくする)
// src/components/CounterMouse.vue
:
:
setup(props) {
// Processing for "count"
let count = ref(0);
const increment = () => {
count.value += 1;
};
const multiplicationResult = computed(() => {
return count.value * props.times;
});
watch(count, () => {
setTimeout(() => {
alert('3 seconds have passed since the value changed');
}, 3000)
})
// Processing for "mousePosition"
const mousePosition = reactive({
x: 0,
y: 0
});
const updateMouse = (event) => {
mousePosition.x = event.clientX
mousePosition.y = event.clientY
};
return {
mousePosition,
count,
increment,
updateMouse,
multiplicationResult
}
},
}
Vue2はオプションごとにまとまっているが、機能ごとにまとめることができる
再利用性をあげる
Vue2でのmixinは処理を追うのを難しくさせる場合があるのと、名前のコンフリクトが起こる可能性がある
// src/components/CounterMouse.vue
:
:
import { ref, computed, watch } from '@vue/composition-api';
import { usePosition } from '../util-functions/position'
export default {
:
:
// Processing for "mousePosition"
// const mousePosition = reactive({
// x: 0,
// y: 0
// });
// const updateMouse = (event) => {
// mousePosition.x = event.clientX
// mousePosition.y = event.clientY
// };
// you can change names to avoid names confliction
const { position: mousePosition, updatePosition: updateMouse } = usePosition();
return {
:
:
multiplicationResult
}
},
}
// src/util-functions/position.js
import { reactive } from '@vue/composition-api'
export const usePosition = () => {
const position = reactive({
x: 0,
y: 0
});
const updatePosition = (event) => {
position.x = event.clientX
position.y = event.clientY
};
return { position, updatePosition }
}
最終的なコード
<template>
<div @mousemove="updateMouse">
<div>
<!-- you can omit ".value" to get the value in template -->
Count is {{ count }}, count * {{ times }} is {{ multiplicationResult }}
<button @click="increment">
+
</button>
</div>
<div>Mouse is at {{ mousePosition.x }}, {{ mousePosition.y }}</div>
</div>
</template>
<script>
// "reactive" can be passed only object as argument
// "ref" can be passed not only object such as Number, String, and so on
// you should access the value with ".value" if you use "ref"
import { ref, computed, watch } from '@vue/composition-api';
import { usePosition } from '../util-functions/position'
export default {
props: {
times: {
type: Number,
default: 2
}
},
// "setup" is executed before "beforeCreate"
// That's why "this" cannot be used
// "setup" has first argument of props
setup(props) {
// Processing for "count"
let count = ref(0);
const increment = () => {
count.value += 1;
};
const multiplicationResult = computed(() => {
return count.value * props.times;
});
watch(count, () => {
setTimeout(() => {
alert('3 seconds have passed since the value changed');
}, 3000)
})
// Processing for "mousePosition"
const { position: mousePosition, updatePosition: updateMouse } = usePosition()
return {
mousePosition,
count,
increment,
updateMouse,
multiplicationResult
}
},
}
</script>