Home  >  Q&A  >  body text

How to implement infinite loop of parent-child components in Vue 2: use slots

<p>I need to call a method of a child component from the parent component. However, something I'm doing in the child component seems to be causing an infinite loop. I've tried looking at other questions and while they seem to be solving a similar problem, I can't apply their exact pattern to the problem I'm facing, it seems to be different. I'm just not sure what I'm looking at. </p> <p>I have two components, one is called ToggleButtons and the other is simplified to a button. Here are the ToggleButtons:</p> <pre class="brush:php;toolbar:false;"><template> <div role="list"> <div role="listitem"> <slot name="left" :is-selected="leftSelected" :toggleLeft="toggle('left')" /> </div> <div role="listitem"> <slot name="right" :is-selected="rightSelected" :toggleRight="toggle('right')" /> </div> </div> </template> <script> export default { props: { leftSelectedInitially: { type: Boolean, default: true, } }, data() { return { leftSelected: true, rightSelected: false, } }, beforeMount() { this.leftSelected = this.leftSelectedInitially; this.rightSelected = !this.leftSelectedInitially; }, methods: { toggle(override) { this.leftSelected = override == 'left'; this.rightSelected = override == 'right'; } } } </script></pre> <p>这是它与按钮的实现:</p> <pre class="brush:php;toolbar:false;"><ToggleButtons ref="tb"> <template v-slot:left="{ isSelected, }"> <button class="button" :class="{ secondary: !isSelected }" :aria-pressed="isSelected" :togglable="true" v-text="'left'" @click="toggle('left')" /> </template> <template v-slot:right="{ isSelected, }"> <button class="button" :class="{ secondary: !isSelected }" :aria-pressed="isSelected" :togglable="true" v-text="'right'" @click="toggle('right')" /> </template> </ToggleButtons></pre> <p>其中toggle方法为:</p> <pre class="brush:php;toolbar:false;">toggle(direction) { this.$refs.tb.toggle(direction); },</pre> <p>正如你可能已经从代码中看到的残留物,我之前尝试过各种模式,包括通过v-slot传递toggle方法。所有这些都导致了相同的“你创建了一个无限循环”的消息。</p> <p>我想知道是否因为该方法在尝试渲染时调用了toggle。我不确定这是否会导致无限循环。我在这里的主要问题是我不明白这个循环是从哪里来的。我目前的主要目标是理解出了什么问题,这样如果再次发生,我就能看到它,即使修复方法只是找到一个更简单的方法。</p>
P粉128563140P粉128563140412 days ago463

reply all(1)I'll reply

  • P粉727531237

    P粉7275312372023-09-04 12:48:32

    The following bindings to the toggle function make no sense to me:

    :toggleLeft="toggle('left')"
    :toggleRight="toggle('right')

    This is an error since the function does not return any value.

    These two bindings will cause infinite function calls toggle('left') and toggle('right')

    Just add console.log(direction) to the toggle function to see what's going on.

    If you would like advice on the correct solution, please describe what you want to achieve.

    Vue.component('toggle-buttons',{
      props: {
        leftSelectedInitially: {
            type: Boolean,
            default: true,
        }
      },
      data() {
          return {
              leftSelected: true,
              rightSelected: false,
          }
      },
      beforeMount() {
          //this.leftSelected = this.leftSelectedInitially;
          //this.rightSelected = !this.leftSelectedInitially;
      },
      methods: {
          toggle(override) {
              console.log(`override: ${override}`)
              this.leftSelected = override == 'left';
              this.rightSelected = override == 'right';
          }
      },
      template: `
    <div role="list">
      <div role="listitem">
          <slot name="left" :is-selected="leftSelected" :toggleLeft="toggle('left')" />
      </div>
      <div role="listitem">
          <slot name="right" :is-selected="rightSelected" :toggleRight="toggle('right')" />
      </div>
    </div>
    `
    });
    
    new Vue({
      el:'#app',
      methods: {
      toggle(direction) {
        console.log(`direction: ${direction}`)
        this.$refs.tb.toggle(direction);
        }
      }
    })
    #app { line-height: 2; }
    [v-cloak] { display: none; }
    <div id="app">
    <toggle-buttons ref="tb">
        <template v-slot:left="{ isSelected }">
            <button
                class="button"
                :class="{ secondary: !isSelected }"
                :aria-pressed="isSelected"
                :togglable="true"
                v-text="'left'"
                @click="toggle('left')"
            />
        </template>
        <template v-slot:right="{ isSelected }">
            <button
                class="button"
                :class="{ secondary: !isSelected }"
                :aria-pressed="isSelected"
                :togglable="true"
                v-text="'right'"
                @click="toggle('right')"
            />
        </template>
    </toggle-buttons>
    </div>
    <script src="https://unpkg.com/vue@2/dist/vue.min.js"></script>

    reply
    0
  • Cancelreply