12
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-10-10

###やりたいこと

  • 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

12
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?