Vue.jsで「Uncaught RangeError: Maximum call stack size exceeded.」のエラーが発生したので、その原因と解決策をメモしておきます。
目次
「Uncaught RangeError: Maximum call stack size exceeded.」による症状
モーダルを押下した際に「Uncaught RangeError: Maximum call stack size exceeded.」のエラーが発生し続け、画面フリーズ。。アクティビティモニタで強制終了させました。
Chromeのデベロッパーツールでログを確認すると、以下でエラーが出ていました。
1 | focusable.length && (focusable[0] as HTMLElement).focus() |
モーダルをフォーカスする際にコールスタックが無限に積まれ続けているみたいです。
つまり、無限に再帰呼び出ししているため、エラーが起きているようです。
「Uncaught RangeError: Maximum call stack size exceeded.」が発生した原因
モーダル 押下時にエラーが発生しているということで、該当箇所のソースコードを確認します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <tr v-for="doc in docs" :key="doc.id"> <span class="crayon-sy">.</span><span class="crayon-sy">.</span><span class="crayon-sy">.</span> <td> <v-row justify="center"> <v-dialog v-model="delete_dialog" persistent max-width="390"> <template v-slot:activator="{ on }"> <v-btn class="mx-2" fab dark small color="red" v-on="on" @click="showDeleteModal(doc)"> <v-icon dark>delete</v-icon> </v-btn> </template> <v-card> <v-card-title class="headline">削除確認モーダル</v-card-title> <v-card-text>削除します。よろしいですか?</v-card-text> <v-card-actions> <v-btn color="green darken-1" text @click="delete_dialog = false">キャンセル</v-btn> <v-btn color="green darken-1" text @click="remove(delete_data)">削除</v-btn> </v-card-actions> </v-card> </v-dialog> </v-row> </td> <span class="crayon-sy">.</span><span class="crayon-sy">.</span><span class="crayon-sy">.</span> </tr> |
<v-btn>でクッリクするとバインドされてモーダル が表示されるのですが、v-forの中にv-dialogのDOMが生成されているため、テーブルにあるデータ分だけ存在してしまっているのです。
データが一個の場合は問題ないのですが、2つ以上になるとv-modelのdelete-dialogが重複してしまうため、エラーが起きていたというわけです。
つまり、今回のようにテーブル内に動的にデータが生成される場合は、delete-dialogを変数にして動的にするか、モーダルをテーブルの外(v-forの外)に出すかしなければなりません。
「Uncaught RangeError: Maximum call stack size exceeded.」の解決策
というわけで、今回はモーダルをテーブルの外に出し、以下のように修正しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | <tr v-for="doc in docs" :key="doc.id"> <span class="crayon-sy">.</span><span class="crayon-sy">.</span><span class="crayon-sy">.</span> <td> <v-btn class="mx-2" fab dark small color="red" @click="showDeleteModal(doc)"> <v-icon dark>delete</v-icon> </v-btn> </td> <span class="crayon-sy">.</span><span class="crayon-sy">.</span><span class="crayon-sy">.</span> </tr> <span class="crayon-sy">.</span><span class="crayon-sy">.</span><span class="crayon-sy">.</span> <v-row justify="center"> <v-dialog v-model="delete_dialog" persistent max-width="390"> <v-card> <v-card-title class="headline">削除確認モーダル</v-card-title> <v-card-text>削除します。よろしいですか?</v-card-text> <v-card-actions> <v-btn color="green darken-1" text @click="delete_dialog = false">キャンセル</v-btn> <v-btn color="green darken-1" text @click="remove(delete_data)">削除</v-btn> </v-card-actions> </v-card> </v-dialog> </v-row> ... <script> export default { data () { return { delete_data: [], delete_dialog: false } }, methods: { showDeleteModal : function(p) { this.delete_data = p this.delete_dialog = true } } } </script> |