Vue.js "Maximum call stack size exceeded" error. Passing data from parent to child failing
Asked Answered
C

6

51

I cannot pass data from parent to child. I am using props, have tried returning data as well - no luck. I have a panel component (which is parent) with data and panelBody component (child)

Panel is as follows:

<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>

My panelBody is:

<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>

Please help! Can't figure out the error "vue.esm.js?65d7:3877 Uncaught RangeError: Maximum call stack size exceeded". WHen I remove the data everything works like it should.

Chomp answered 13/6, 2017 at 11:26 Comment(4)
You should not use => functions with data property,, just use data(){return{...}}Eisenhower
Did it work...??Eisenhower
no unfort, i get a "Property or method "shelfs" is not defined on the instance but referenced during render" and a "The "data" option should be a function that returns a per-instance value in component definitions." which is odd.Chomp
Nuxt users: I encountered this error when introducing a new component in a template. As a quick workaround, I wrapped the component with <client-only></client-only> and that alleviated the error, while I nailed down the ultimate culprit.Parsifal
M
120

The reason you have the error

Maximum call stack size exceeded

is because of this

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

You defined your Panel component with name: 'panel-body'. Change that to name: 'panel', and you will remove your circular reference.

The other issues mentioned in comments and the other answer generally apply as well. Here are working versions of your components.

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>

I wanted to note one more thing. Because of this line in PanelBody, this.selected = this.shelf Vue will throw a warning that you are mutating a prop directly. Generally you should store a local copy of a property that you are going to mutate. I've updated the code above to do that.

Malanie answered 13/6, 2017 at 15:53 Comment(4)
@TeomanKirac you're welcome. There is one additional problem not currently covered; this code will produce a error that you are mutating a prop directly. I will post a fix for that in a minute.Malanie
@TeomanKirac I updated the PanelBody code with a quick explanation.Malanie
also see github.com/vuejs/vue/issues/9081 where I reported this to VueErasion
My issue was that my page name (max-button) was the same as the component name (MaxButton, which also works as max-button).Rehearing
L
17

The name of the Vue you are in should not equal the name of the component you are importing.

In my case

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

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

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

The above code was causing the same issue, but when i changed the name of the exported component it worked.

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

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

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

Please check your naming conventions for all future people :)

Langer answered 30/4, 2019 at 23:36 Comment(1)
Yes this was the case for me too but my method was the same name as a mapped action.Capstan
T
3

Try to disable vue dev-tools extension...

I had this erratic error for months in my app, and it drove me crazy ! I just realized that it never happen again if I disable vue dev-tool chrome extension.

Not perfect but it could help.

Tenuto answered 5/1, 2022 at 17:12 Comment(1)
I was seeing the call stack explosion only in certain situations; maybe vuex-related, maybe not. A browser restart worked for me; opening in a new tab didn't seem sufficient. And of course not until after I'd upgraded npm, walked back and forth along the commit history a couple of times, and tried it on a separate machine.Unprecedented
E
2

In my case, it happened when store overflow

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

I updated like this and fixed up this issue. hope this would help you.

const auth =  function({ next, store }){
    if(store.getters.auth.loggedIn){
      return next('/login')
    }
    return next()
}
  
export {auth};
Excellence answered 22/7, 2021 at 0:48 Comment(0)
C
1

the sync has changed in vue2.

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

you should use it this way

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

and on child

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

OR you could do just this

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

and on child

this.$emit("select")
Commitment answered 13/6, 2017 at 11:39 Comment(3)
You're right, but not quite. You can use prop.sync="parentProp" as in the question, it AUTO expands to prop-event declarations. The only thing should be changed in the question code: instead of manually mutating props this.selected = this.shelf there should be this.$emit('update:selected', this.shelf). Example: jsfiddle.net/wostex/63t082p2/72Propylene
have tried all variations of what John and Wostex have suggested with no luck. The error now is "Property or method "shelfs" is not defined on the instance but referenced during render." But this error is only different cause the data is not a function now, like Vamsi Krishna suggested..Chomp
the data must be a function data: function(){ return {bla: true} }Commitment
C
0

I was doing something like this:

  watch: {
    topics() {
      this.topics = this.topics.slice(0, 40);
    },
  },

Each time, it creates a new array with new reference, that should be done with splice:

 topics() {
    this.topics.splice(40);
 },
Cesarean answered 10/10, 2022 at 13:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.