Edited at

v-for内の子コンポーネントのメソッドを親から$refsで呼ぶときにエラーが出てしまうときの対処法


やりたいこと


  • v-forの中で子コンポーネントを複数作る

  • 親コンポーネントからそれぞれの子コンポーネントのメソッドを呼びたい


前提

親コンポーネントから子コンポーネントのメソッドを呼びたい時、$refsを使えば可能です。


App.vue

    //親コンポーネント

<template>
<div id="app">
<button @click="callChildMethod">Change Message</button>
<!-- 子コンポーネントにref属性を付けて参照出来るようにする -->
<HelloWorld ref="child"/>
</div>
</template>

<script>
import HelloWorld from './components/HelloWorld'

export default {
name: 'App',
methods: {
callChildMethod(){
//子コンポーネントのメソッドを呼ぶ
this.$refs.child.changeMsg();
}
},
components: {
HelloWorld
}
}
</script>



HelloWorld.vue


//子コンポーネント
<template>
<div class="hello">
<p>{{ msg }}</p>
</div>
</template>

<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Hello!'
}
},
methods: {
changeMsg(){
this.msg = 'Hi!';
}
}
}
</script>



v-for内の場合

しかし、v-for内でこの手法を使おうとするとUncaught TypeError: this.$refs.child.changeMsg is not a functionとエラーが出てしまいます。


App.vue

    <template>

<div id="app">
<!-- 子コンポーネントをv-forで複数個作る -->
<div v-for="n in 3" :key="n">
<button @click="callChildMethod">Change Message</button>
<HelloWorld ref="child"/>
</div>
</div>
</template>

<script>
import HelloWorld from './components/HelloWorld'

export default {
name: 'App',
methods: {
callChildMethod(){
this.$refs.child.changeMsg();
//→Uncaught TypeError: this.$refs.child.changeMsg is not a function
}
},
components: {
HelloWorld
}
}
</script>



対処法

その場合はv-forの引数として提供されているindexを渡してあげれば解決します。


App.vue

    <template>

<div id="app">
<!-- v-forの引数でindexを指定 -->
<div v-for="(n, index) in 3" :key="n">
<!-- メソッドにindexを渡す -->
<button @click="callChildMethod(index)">Change Message</button>
<HelloWorld ref="child"/>
</div>
</div>
</template>

<script>
import HelloWorld from './components/HelloWorld'

export default {
name: 'App',
methods: {
callChildMethod(index){
//this.$refs.参照ID[index].子のメソッド()の形で呼ぶ
this.$refs.child[index].changeMsg();
}
},
components: {
HelloWorld
}
}
</script>


vue_component.gif


注意点

ただしコンポーネント同士が密結合になってしまい良くないので、あくまで小規模なものの中で使うようにして、大規模なものに関してはvuexを使うようにした方が後々幸せになれるかもしれません。


参考

https://laracasts.com/discuss/channels/vue/child-and-refs-not-a-function