Vue.js“超出最大调用堆栈大小”错误。将数据从父母传递给孩子失败

Posted

技术标签:

【中文标题】Vue.js“超出最大调用堆栈大小”错误。将数据从父母传递给孩子失败【英文标题】:Vue.js "Maximum call stack size exceeded" error. Passing data from parent to child failing 【发布时间】:2017-11-15 03:43:22 【问题描述】:

我无法将数据从父母传递给孩子。我正在使用道具,也尝试过返回数据 - 没有运气。我有一个带有数据的面板组件(它是父组件)和 panelBody 组件(子组件)

面板如下:

<template>
  <div id="panel">
    <div class="panel">
      <ul>
        <li v-for="shelf in shelfs">
          <panel-body :shelf="shelf" :selected.sync="selected"></panel-body>
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
import PanelBody from '../components/PanelBody'
export default 
  name: 'panel-body',
  components: 
    'panel-body': PanelBody
  ,
  data: () => (
    shelfs: [
      name: 'shelf 1',
      books: [
        title: 'Lorem ipum'
      , 
        title: 'Dolor sit amet'
      ]
    , 
      name: 'shelf 2',
      books: [
        title: 'Ipsum lorem'
      , 
        title: 'Amet sit dolor'
      ]
    ],
    selected: 
  )

</script>

<style scoped>
a 
  color: #42b983;

</style>

我的 panelBody 是:

<template>
  <div id="panel-body">
    <a href="#" v-on:click.prevent.stop="select"> shelf.name </a>
    <ul v-show="isSelected">
      <li v-for="book in shelf.books"> book.title </li>
    </ul>
  </div>
</template>

<script>
export default 
  name: 'panel-body',
  props: ['shelf', 'selected'],
  computed: 
    isSelected: function () 
      return this.selected === this.shelf
    
  ,
  methods: 
    select: function () 
      this.selected = this.shelf
    
  

</script>

<style scoped>
a 
  color: #42b983;

</style>

请帮忙!无法找出错误“vue.esm.js?65d7:3877 Uncaught RangeError: Maximum call stack size exceeded”。当我删除数据时,一切正常。

【问题讨论】:

你不应该使用带有 data 属性的=&gt; 函数,只使用data()return... 成功了吗...?? 不,我得到一个“属性或方法“架子”未在实例上定义,但在渲染期间被引用”和““数据”选项应该是一个返回每个实例的函数组件定义中的价值。”这很奇怪。 【参考方案1】:

出现错误的原因

超过最大调用堆栈大小

是因为这个

import PanelBody from '../components/PanelBody'
export default 
  name: 'panel-body',
  components: 
    'panel-body': PanelBody
  ,

您使用name: 'panel-body' 定义了您的面板 组件。将其更改为 name: 'panel',您将删除循环引用。

cmets 和其他答案中提到的其他问题通常也适用。以下是您的组件的工作版本。

Panel.vue

<template>
  <div id="panel">
    <div class="panel">
      <ul>
        <li v-for="shelf in shelfs">
          <panel-body :shelf="shelf" :key="shelf.name" :selected.sync="selected"></panel-body>
        </li>
      </ul>
    </div>
    selected
  </div>
</template>

<script>
import PanelBody from './PanelBody.vue'
export default 
  name: 'panel',
  components: 
    'panel-body': PanelBody
  ,
  data()
    return 
    shelfs: [
      name: 'shelf 1',
      books: [
        title: 'Lorem ipum'
      , 
        title: 'Dolor sit amet'
      ]
    , 
      name: 'shelf 2',
      books: [
        title: 'Ipsum lorem'
      , 
        title: 'Amet sit dolor'
      ]
    ],
    selected: 

    
  

</script>

<style scoped>
a 
  color: #42b983;

</style>

PanelBody.vue

<template>
  <div id="panel-body">
    <a href="#" v-on:click.prevent.stop="select"> shelf.name </a>
    <ul v-show="isSelected">
      <li v-for="book in shelf.books"> book.title </li>
    </ul>
  </div>
</template>

<script>
export default 
  name: 'panel-body',
  props: ['shelf', 'selected'],
  data()
    return 
      internalSelected: null
    
  ,
  computed: 
    isSelected: function () 
      return this.internalSelected === this.shelf
    
  ,
  methods: 
    select: function () 
      this.internalSelected = this.shelf
      this.$emit("update:selected", this.internalSelected)
    
  

</script>

<style scoped>
a 
  color: #42b983;

</style>

我还想注意一件事。由于 PanelBody 中的 this 行,this.selected = this.shelf Vue 会抛出一个警告,表明你正在直接改变一个 prop。通常,您应该存储要更改的属性的本地副本。我已经更新了上面的代码来做到这一点。

【讨论】:

@TeomanKirac 不客气。目前还没有涉及一个额外的问题;此代码将产生一个错误,即您正在直接改变一个道具。我会在一分钟内发布一个修复。 @TeomanKirac 我更新了 PanelBody 代码并简要说明。 伯特先生,你太棒了。非常感谢您的解释和专业知识。非常感谢:) 另见 github.com/vuejs/vue/issues/9081 我向 Vue 报告了这一点 我的问题是我的页面名称(max-button)与组件名称(MaxButton,也可以用作max-button)相同。【参考方案2】:

您所在的 Vue 的名称不应与您正在导入的组件的名称相同。

就我而言

<template>
 <div>
    <SingleStandard></SingleStandard>
 </div>
</template>

<script>
    import SingleStandard from '../components/SingleStandard';

    export default 
      name: 'SingleStandard',
      components:  SingleStandard ,
    ;
</script>

上面的代码导致了同样的问题,但是当我更改导出组件的名称时它起作用了。

<template>
 <div>
    <SingleStandard></SingleStandard>
 </div>
</template>

<script>
    import SingleStandard from '../components/SingleStandard';

    export default 
      name: 'SingleStandardView', <-------------
      components:  SingleStandard ,
    ;
</script>

请为所有未来的人检查您的命名约定:)

【讨论】:

是的,我也是这种情况,但我的方法与映射操作同名。【参考方案3】:

vue2 中的同步发生了变化。

https://vuejs.org/v2/guide/components.html#sync-Modifier

你应该这样使用它

<panel-body :shelf="shelf" :selected="selected" @update:selected="val => selected = val"></panel-body>

和孩子

this.$emit('update:selected', shelf)

或 你可以这样做

<panel-body :shelf="shelf" :selected="shelf == selected" @select="selected = shelf"></panel-body>

和孩子

this.$emit("select")

【讨论】:

你是对的,但并不完全正确。您可以在问题中使用prop.sync="parentProp",它自动扩展为道具事件声明。唯一应该在问题代码中更改:而不是手动改变道具this.selected = this.shelf,应该是this.$emit('update:selected', this.shelf)。示例:jsfiddle.net/wostex/63t082p2/72 已经尝试了 John 和 Wostex 建议的所有变体,但没有成功。现在的错误是“属性或方法“架子”未在实例上定义,但在渲染期间被引用。”但是这个错误只是不同的,因为数据现在不是一个函数,就像 Vamsi Krishna 建议的那样.. 数据必须是函数数据:function() return bla: true 【参考方案4】:

在我的情况下,它发生在商店溢出时

const auth =  function( next, store )
    if(!store.getters.auth.loggedIn)
      return next('/login')
    
    return next()

  
export auth;

我像这样更新并修复了这个问题。希望这会对你有所帮助。

const auth =  function( next, store )
    if(store.getters.auth.loggedIn)
      return next('/login')
    
    return next()

  
export auth;

【讨论】:

【参考方案5】:

尝试禁用 vue dev-tools 扩展...

我的应用程序中有几个月出现这个不稳定的错误,这让我发疯了! 我刚刚意识到,如果我禁用 vue dev-tool chrome 扩展,它就再也不会发生了。

不完美,但它可以提供帮助。

【讨论】:

以上是关于Vue.js“超出最大调用堆栈大小”错误。将数据从父母传递给孩子失败的主要内容,如果未能解决你的问题,请参考以下文章

如何修复“超出最大调用堆栈大小”错误

Angular 11最大调用堆栈大小超出错误

Nuxt 超出最大调用堆栈大小

如何捕获“超出最大调用堆栈大小”错误?

npm 错误!超出最大调用堆栈大小

递归过多/超出最大调用堆栈大小(Jquery 1.9.1)