【Vue】親子間値受け渡しを✅
ブシトラさんと武蔵小杉の渡来部に行ってきました。ブシ渡来部ですね。何つって。殴っていいですよ。近所っていいですね。
そしてチームが決まりました。来年の2月からチーム開発を開始していきます。楽しみですね〜〜
さて、今回は親子間で値を受け渡す千本ノックをしていきたいと思います。
親子コンポーネントの値受け渡しとは
二つのコンポーネント間でv-bindやv-onを使って値の受け渡しをすること。
一つのコンポーネントは一つの役割を持つという前提で分割を進める。そうすることでコードの冗長化を防ぐ。rubyでいうpartial。
分割されたコンポーネントを、さらに値を渡す側(親)と値を受け取る側(子)に分類。
ここでいう子は、ボタンやインプットフォーム、ヘッダーなど、一つの役割だけを持ったコンポーネントを指す。
そして親は、子を複数入れることで機能するコンポーネントを指す。
値の受け渡しにおいて重要な概念
props
配列でdataのプロパティを渡す
親⇨子にコンポーネントを渡すときはpropsを使う。
紛らわしいのが、親⇨子という流れなのに、コンポーネントをインポートしているのは親だということ。日本語的に、コンポーネントを「渡される」対象が子なら、子がインポートするのが普通なのではと思う。
#src/components/Child.vue
<template>
<div>
<p>{{ statement }}</p>
</div>
</template>
<script>
export default {
props: {
statement: {
type: String,
default: 'hogehoge'
}
}
#propsの名前と型を子コンポーネント内で定義している。
}
</script>
補足:
propsの名前と型を子コンポーネント内で定義している。
#src/pages/App.vue
<template>
<div>
<h1>Hello from App.vue</h1>
<Child statement='choose to go to the moon.'/>
#ChildのgreetをHello with propsという値に上書きしている。
</div>
</template>
<script>
import Child from './components/Child.vue'
#子コンポーネントを親コンポーネントがインポートしている。
export default {
components: {
Child
#childにコンポーネントを渡している。
}
}
</script>
補足:
ChildのgreetをHello with propsという値に上書きしている。
ポイント
$emit
子⇨親にコンポーネントを渡している。
src/components/Child.vue
<template>
<div>
<p>subordinate_num: {{ subordinate_num }}</p>
<button @click='send'>君主に値を渡す</button>
</div>
</template>
<script>
export default {
data() {
return {
subordinate_num: 0
};
},
methods: {
send() {
this.$emit("my-click", this.subordinate_num);
#親コンポーネントでは、子で定義していたsend()アクションをmy-clickという名前で実行できる。
}
}
};
</script>
補足:
this.$emit("my-click", this.subordinate_num);
とすることで、親コンポーネントでは、子で定義していたsend()アクションをmy-clickという名前で実行できる。
#src/pages/App.vue
# パターン1:受け取った値をそのまま使う場合は$eventで受け取る
<template>
<div>
<h1>Hello from App.vue</h1>
<p>lord_num: {{ lord_num }}</p>
<Child @my-click='lord_num = $event'/>
#受け取った値を@に続いた形で記述。
#バインドさせた値 = $eventと書くことで、そのまま使用できる。
</div>
</template>
<script>
import Child from './components/Child.vue'
export default {
data() {
return {
lord_num: 100
}
},
components: {
Child
}
}
</script>
補足:
受け取った値を@に続いた形で記述。 バインドさせた値 = $eventと書くことで、そのまま使用できる。
実際に使ってみる
radio button
まずは親に全てを記述する
<template>
<v-container
class="px-0"
fluid
>
<v-radio-group v-model="radioGroup" >
<v-radio
v-for="n in 3"
:key="n"
:label="`Radio ${n}`"
:value="n"
></v-radio>
</v-radio-group>
</v-container>
</template>
<script>
export default {
data () {
return {
radioGroup: 1,
}
},
};
</script>
動きは以下の通り
それでは親子コンポーネントに分けていく。
v-modelを使った場合
RadioParent.vue
<template>
<v-container class="px-0" fluid>
<p>Parent: {{ radioGroup }}</p>
<RadioChild v-model="radioGroup" />
</v-container>
</template>
<script>
import RadioChild from '../components/forms/RadioChild.vue';
export default {
components: {
RadioChild,
},
data() {
return {
radioGroup: 1,
};
},
};
</script>
RadioChild.vue
<template>
<v-container class="px-0" fluid>
<p>Child: {{ childRadio }}</p>
<v-radio-group v-model="childRadio">
<v-radio v-for="n in 3" :key="n" :label="`Radio ${n}`" :value="n"></v-radio>
</v-radio-group>
</v-container>
</template>
<script>
export default {
props: {
value: {
type: String,
},
},
data() {
return {
radioGroup: 1,
};
},
computed: {
childRadio: {
get() {
return this.value;
},
set(newValue) {
this.$emit('input', newValue);
},
},
},
};
</script>
動きを確認する
select form
クリックしたら項目がずらっと出てくるようなフォームを作る。
SelectParent.vue
<template>
<div>
<p>{{selected}}</p>
<SelectChild
:options="options"
:selected="selected"
@select="$emit('select', $event)"
/>
</div>
</template>
<script>
import SelectChild from '../components/forms/SelectChild.vue';
export default {
components: {
SelectChild
},
props: {
selected: {
type: Array,
required: true
}
},
data: () => ({
options: [
{ text: 'hoge1', value: 'hoge1' },
{ text: 'hoge2', value: 'hoge2' }
]
})
}
</script>
SelectChild.vue
<template>
<select
v-model="select"
multiple
>
<option
v-for="(option, key) in options"
:key="key"
:value="option.value"
>
{{ option.text }}
</option>
</select>
</template>
<script>
export default {
props: {
selected: {
type: Array,
required: true
},
options: {
type: Array,
required: true
}
},
computed: {
select: {
get () {
return this.selected;
},
set (value) {
this.$emit('select', value);
}
}
}
};
</script>
実際の動きを見てみる
【Vue/Nuxt】multipleなselectのデータを親子間で受け渡すには?
button
クリックされたら親コンポーネントにある値を変化させるだけのボタンコンポーネントを作る。
ButtonParent.vue
<template>
<div class="parent">
<p>Parentnum: {{num}}</p>
<ButtonChild @parent-event="parentEvent" />
</div>
</template>
<script >
import ButtonChild from '../components/forms/ButtonChild.vue';
export default {
components: {
ButtonChild,
},
data(){
return{
num: 1,
}
},
methods: {
parentEvent() {
this.num += 1;
}
}
}
</script>
ButtonChild.vue
<template>
<div class="child">
<v-btn color="primary" @click="childEvent">クリック</v-btn>
</div>
</template>
<script >
export default {
methods: {
childEvent() {
//親にparent-eventを渡している
this.$emit('parent-event')
}
}
}
</script>
実際の動き。親子間で値を渡すことができている。
変数を渡す方法もある。
ButtonChild.vue
<template>
<div class="child">
<p>child_num: {{child_num}}</p>
<v-btn color="primary" @click="childEvent">クリック</v-btn>
</div>
</template>
<script >
export default {
data: function() {
return {
child_num: 0
};
},
methods: {
childEvent() {
//親にparent-eventを渡している
this.$emit('parent-event', this.child_num)
}
}
}
</script>
ButtonParent.vue
<template>
<div class="parent">
<p>Parentnum: {{num}}</p>
<ButtonChild @parent-event="parentEvent" />
</div>
</template>
<script >
import ButtonChild from '../components/forms/ButtonChild.vue';
export default {
components: {
ButtonChild,
},
data(){
return{
num: 5,
}
},
methods: {
parentEvent(value) {
this.num += (value + 1);
}
}
}
</script>
実際の挙動
まとめ
後書き
明日のポートフォリオレビュー会が恐ろしい、、