Vue APP组件报Maximum recursive updates exceeded警告如何解决
问题原因分析
- 死循环触发链路:
mounted钩子中直接修改squares、player两个响应式变量,会触发组件重渲染,重渲染完成后就会调用updated钩子;如果$session操作、或者取值异常导致的报错触发了二次重渲染,就会陷入「更新→触发updated→再次触发更新」的无限递归。 - 逻辑不合理:
updated钩子会在任意响应式变量变化导致DOM更新时触发,你只需要在squares和player变化时存session,放在updated里会大量执行无用操作,也更容易触发意外更新。 - 取值无兜底:如果session中没有对应存储值,
this.$session.get会返回undefined,直接赋值给squares会让它从数组变为undefined,后续代码调用squares.filter、squares.splice等数组方法会抛出异常,进一步触发异常更新。
修复方案
直接替换mounted和updated的代码逻辑,改用watch监听需要持久化的变量即可:
<script> import Box from './Box.vue'; import PlayStatus from './PlayStatus.vue'; import Restart from './Restart.vue'; import getWinner from '../utils/winner'; export default { components: { Box, PlayStatus, Restart }, data() { return { player: 'X', squares: Array(9).fill(null), }; }, computed: { winner() { return getWinner(this.squares); }, isDraw() { return this.squares.filter((square) => !square).length === 0; }, }, // 新增watch监听变量变化,自动存session watch: { squares: { deep: true, // 监听数组内部元素的变化 handler(newVal) { // 如果你的$session插件没有自动序列化,需要手动转JSON:this.$session.set('board', JSON.stringify(newVal)) this.$session.set('board', newVal); } }, player(newVal) { this.$session.set('player', newVal); } }, methods: { clickSquare(index) { if (this.squares[index]) { return; } this.squares.splice(index, 1, this.player); this.player = this.player === 'X' ? 'O' : 'X'; if (this.winner || this.isDraw) { return; } }, resetGame() { this.player = 'X'; this.squares.fill(null); }, }, mounted() { // 取值加兜底,避免session无值时变量类型异常 // 如果你的$session插件没有自动反序列化,需要手动解析:this.squares = this.$session.get('board') ? JSON.parse(this.$session.get('board')) : Array(9).fill(null) this.squares = this.$session.get('board') || Array(9).fill(null); this.player = this.$session.get('player') || 'X'; } }; </script>
额外注意点
如果你的$session是自己封装的基础工具,没有做JSON序列化/反序列化处理,需要按照代码注释里的写法手动转格式,因为sessionStorage原生只能存储字符串类型,直接存数组会被转成[object Array]的无效字符串,取出后无法正常使用。
内容的提问来源于stack exchange,提问作者Linas AdrenaLinas
相关产品推荐
相关产品推荐

