Help us understand the problem. What is going on with this article?

You may have an infinite update loop in a component render function. 問題の調査

tl;dr

  • Vueでconsoleに [Vue warn]: You may have an infinite update loop in a component render function. が表示される
  • render中にdataを変更してしまい、これによって再度renderが呼ばれることが原因
  • Array.prototype.sort() は対象配列を変更する破壊的メソッドなので注意が必要

概要

Vueはモデルが変更されるとリアクティブにビューを変更してくれるので便利なのですが、利用に際して気をつけなければならないこともあります。
その一つが、rendering時の無限ループです。

rendering時の無限ループは次のようなものです。
1. renderが実施される
2. render中にモデル(data)が変更される
3. モデルの変更によって再度renderが実施される
4. render中にモデルが変更される
5. モデルの変更によって再度renderが実施される
...

rendering時に無限ループが発生した場合、次のようなwarningをconsoleに出力して無限ループを止めてくれる機能1がVueにあるため極端に恐れることはないのですが、意図していない動作となるためこのwarningが出ていたら対処するのが吉です。

[Vue warn]: You may have an infinite update loop in a component render function.

found in

---> <App> at src/App.vue
       <Root>

update loopが起きるパターン

templateでdataを変更している

一番かんたんな例です。
template中でcounter++とすることでcounterの値を変更しています。

<template>
  <div id="app">
    <div>{{counter++}}</div>
  </div>
</template>

<script>
export default {
  name: 'app',
  data: () => {
    return {
      counter: 0,
    }
  },
}
</script>

解決方法

基本的にtemplate内でdataの変更をしたいことはないはずです。(あったら教えて下さい)

methodでdataを変更している

render中に利用するmethodがdataを変更していても無限ループが起きます。

<template>
  <div id="app">
    <div>{{count()}}</div>
  </div>
</template>

<script>
export default {
  name: 'app',
  data: () => {
    return {
      counter: 0,
    }
  },
  methods: {
    count() {
      this.counter++
    }
  }
}
</script>

解決方法

データを変更する可能性のあるメソッドが描画で呼ばれるのが間違いなので、メソッドの適切な分割をします。

computedでdataを変更している

computedの場合はエラーで止めてくれるため、基本的にはこのパターンは大丈夫な気がします

<template>
  <div id="app">
    <div>{{count()}}</div>
  </div>
</template>

<script>
export default {
  name: 'app',
  data: () => {
    return {
      counter: 0,
    }
  },
  computed: {
    count() {
      return this.counter++
    }
  }

}
</script>
Failed to compile.

./src/App.vue
Module Error (from ./node_modules/eslint-loader/index.js):
error: Unexpected side effect in "count" computed property (vue/no-side-effects-in-computed-properties) at src/App.vue:17:14:
  15 |   computed: {
  16 |     count() {
> 17 |       return this.counter++
     |              ^
  18 |     }
  19 |   }
  20 | 

1 error found.

解決方法

dataに変更を加えないよう変更します。

  computed: {
    count() {
      return this.counter + 1
    }
  }

配列に変更メソッドを使用してしまっている

1番目のパターンと同じです。
配列データを並べ替えて表示するときにsort()を利用すると思いますが、これは元の配列を変更する破壊的メソッドです。つまり、array.sort() によって並び替えられた新しい配列が返されるのではなく、array自身が並び替えられて返されます。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

sort()の他にはreverse()等も同様。
https://vuejs.org/v2/guide/list.html#Mutation-Methods

<template>
  <div id="app">
    <div v-for="item in array.sort((a, b) => a.value - b.value)" :key="item.name">
        {{item.name}}: {{item.value}}
    </div>
  </div>
</template>

<script>
export default {
  name: 'app',
  data: () => {
    return {
      array: [
        {
          name: 'a',
          value: 20,
        }, {
          name: 'b',
          value: 50,
        }, {
          name: 'c',
          value: 10
        }
      ]
    }
  },
}
</script>

一応表示はされますが、先述のwarningがでます。
スクリーンショット 2020-02-03 11.40.47.png

解決方法

arrayをslice()で新しい配列にコピーした上で、新しい配列を並び替えします。
こうすることでarray自身は変更されなくなります。
[...array].sort()等でも可

<template>
  <div id="app">
    <div v-for="item in array.slice().sort((a, b) => a.value - b.value)" :key="item.name">
        {{item.name}}: {{item.value}}
    </div>
  </div>
</template>

まとめ

javascriptの Array.prototype.sort() は元配列をin placeに変更するので注意。


  1. defaultで100回ループしたら停止します 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした