Vue.js Ошибка "Максимальный размер стека вызовов". Передача данных с родительского на отказ от детей

Я не могу передавать данные от родителя к дочернему. Я использую реквизит, попробовал возвращать данные - не повезло. У меня есть компонент панели (который является родительским) с компонентами data и 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>

Моя панель:

<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: Максимальный размер стека вызовов". Когда я удаляю данные, все работает так, как должно.

Ответ 1

Причина, по которой у вас есть ошибка

Максимальный размер стека вызовов

из-за этого

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

Вы определили компонент Panel с name: 'panel-body'. Измените это, чтобы name: 'panel', и вы удалите свою круговую ссылку.

Другие вопросы, упомянутые в комментариях и другом ответе, как правило, также применяются. Вот рабочие версии ваших компонентов.

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.selected = this.shelf Vue выдаст предупреждение о том, что вы напрямую мутируете prop. Как правило, вы должны сохранить локальную копию свойства, которое вы собираетесь мутировать. Для этого я обновил код выше.

Ответ 2

синхронизация изменилась в 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")

Ответ 3

Имя 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>

Пожалуйста, проверьте ваши соглашения об именах для всех будущих людей :)