2024-09-09
コメントでいただいた件を修正しました。
setupする
スクリプトタグにsetupを追加する
<script setup lang="ts">
defineXxxはimportに書かない
キホンの木
<script setup lang="ts">
defineProps({
hoge: { type: String, default: "" }
});
const emit = defineEmits(['render']);
defineExpose({
onClick: () => {}
});
// など
defineProps内の型の書き方
String, Number, Array, Object, Boolean以外の書き方
<script setup lang="ts">
import { PropType, withDefaults } from 'vue';
type Hoge { id: number };
interface Props {
hoge?: Hoge;
hoges?: Hoge[];
}
withDefaults(defineProps<Props>(), {
hoge: undefined,
hoges: () => []
});
reactiveな変数にはref or reactiveをつける
よく使う
<script setup lang="ts">
import { ref } from 'vue';
const isOpen = ref(false);
const toggleOpen = () => {
isOpen.value = !isOpen.value;
}
... 省略 ...
<template>
<!-- ここでは.valueは書かなくてOK --!>
<Modal :open="isOpen">
オブジェクトの場合はreactiveがラク
<script setup lang="ts">
import { reactive } from 'vue';
const statuses = reactive({ isOpenA: true, isOpenB: false });
const toggleOpenA = () => {
statuses.isOpenA = !statuses.isOpenA;
}
refにコンポーネントを設定する 〜 親から子の関数を実行する
よく忘れるし、親コンポーネントから子コンポーネントの関数を叩くのはあまりない
Childコンポーネント
<script setup lang="ts">
import { ref } from 'vue';
import Hoge from './hoge.vue';
const hoge = ref<InstanceType<typeof Hoge> | null>(null);
const onClickHoge = () => {
hoge?.value?.onClick?.();
}
... 省略 ...
<template>
<Hoge ref="hoge">
Parentコンポーネント
<script setup lang="ts">
defineExpose({
onClick: () => {} // ←これが親から呼ばれる
})
refの余談
Vitestでテストを運用している + onMounted内でrefを更新している場合、
VitestがonMountedの更新を待たずにスナップショット撮るケースがあり、
以下で回避できる
import { nextTick } from 'vue';
import Hoge from './hoge.vue';
describe('ほげ', () => {
it('ほげほげ', async () => {
const wrapper = shallowMount(Hoge);
await nextTick(); // onMountedが完了するのを待つ
expect(wrapper.element).toMatchSnapshot();
});
});
emitは$eventもしくは「...」で受け取る
呼び出し元のコンポーネントでご自由にどうぞ
Childコンポーネント
const emit = defineEmits(['open', 'close']);
const onOpen = () => {
emit('open', true)
}
const onClose = () => {
emit('close', true, false, 123)
}
Parentコンポーネント
const onClose = (...args) => {
console.log(args); // [true, false, 123];
}
... 省略 ...
<template>
<Child @open="isOpen = $event" @close="onClose" />
更新可能なcomputedはgetter, setterを使う
emitとの連携がある場合にはすっきり書ける
const props = defineProps<{ isOpen: boolean }>();
const emit = defineEmits(['open'])
const open = computed({
get: () => props.isOpen,
set: (val) => emit('open', val),
});