【问题标题】:How to solve Avoid mutating a prop directly since the value will be overwritten如何解决避免直接改变道具,因为值将被覆盖
【发布时间】:2020-09-12 12:42:51
【问题描述】:

我看到了很多问题和答案,但它们并没有解决我的问题,我只是想在单击父组件菜单按钮时显示/隐藏抽屉应该打开,第一次加载后它可以工作很好,但是当我关闭它时,它会显示这个错误。我只是想在道具中传递真假

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "drawer"

这就是我想要做的。

在父级中

<template>
    <div @click="drawer = true" class="hamburger">
       <span></span>
       <span></span>
       <span></span>
    </div>

   <mobile-drawer-menu :drawer="drawer"/>
</template>

<script>
   import MobileDrawerMenu from "./MobileDrawerMenu";

   export default {
     components : {
        MobileDrawerMenu
    },

     data() {
        return {
            drawer : false,
        }
     },

   }
</script>

在孩子中

<template>
    <div v-if="drawer" class="fixed top-0 left-0 z-200">
        <div @click="drawer = false" class="overlay"></div>
        <div class="drawer-wrapper">
            <div class="drawer-close">
               <div class="flex items-center justify-end">
                  <svg @click="drawer = false"></svg>
               </div>
            </div>
        </div>
    </div>                     
</template>

<script>
   export default {
      name: "MobileDrawerMenu",
      props : {
        drawer : {
            type : Boolean,
            required : true
        }
     },
   }
</script>

【问题讨论】:

    标签: vue.js


    【解决方案1】:

    您可以使用.sync modifier,并使用$emit 更新道具:

    <template>
        <div @click="drawer = true" class="hamburger">
           <span></span>
           <span></span>
           <span></span>
        </div>
    
       <mobile-drawer-menu :drawer.sync="drawer"/>
    </template>
    
    <script>
       import MobileDrawerMenu from "./MobileDrawerMenu";
    
       export default {
         components : {
            MobileDrawerMenu
        },
    
         data() {
            return {
                drawer : false,
            }
         },
    
       }
    </script>
    

    儿童

    <template>
        <div v-if="drawer" class="fixed top-0 left-0 z-200">
            <div @click="$emit('update:drawer', false)" class="overlay"></div>
            <div class="drawer-wrapper">
                <div class="drawer-close">
                   <div class="flex items-center justify-end">
                      <svg @click="$emit('update:drawer', false)"></svg>
                   </div>
                </div>
            </div>
        </div>                     
    </template>
    
    <script>
       export default {
          name: "MobileDrawerMenu",
          props : {
            drawer : {
                type : Boolean,
                required : true
            }
         },
       }
    </script>
    

    JsFiddle:https://jsfiddle.net/hansfelix50/176oba9n/

    【讨论】:

    • 不,.sync 是在内部创建 @update 并更新父属性的简写
    • 是的,但是当子组件依赖于父组件时,情况就剩下了。我认为 ref 更好。不过这个解决方案也不错。
    • 它现在告诉我这个错误Error in v-on handler: "TypeError: handler.apply is not a function"@Hans
    • 是的,这个工作:),谢谢你们两个,你们真的很棒
    【解决方案2】:

    您不应该在子组件中改变您的道具。您可以在父控制器中发出事件并关闭,或者让drawer 仅在子组件中并通过函数切换打开,使用参考:

    家长:

    <template>
        <div @click="open" class="hamburger">
           <span></span>
           <span></span>
           <span></span>
        </div>
    
       <mobile-drawer-menu ref="modal"/>
    </template>
    
    <script>
        import MobileDrawerMenu from "./MobileDrawerMenu";
    
        export default {
            components : {
                MobileDrawerMenu
            },
            methods: {
                open() {
                    this.$refs.modal.open();
                }
            },
        }
    </script>
    

    孩子:

    <template>
        <div v-if="drawer" class="fixed top-0 left-0 z-200">
            <div @click="close" class="overlay"></div>
            <div class="drawer-wrapper">
                <div class="drawer-close">
                   <div class="flex items-center justify-end">
                      <svg @click="close"></svg>
                   </div>
                </div>
            </div>
        </div>                     
    </template>
    
    <script>
        export default {
            name: "MobileDrawerMenu",
            data: () => ({
                drawer: false
            }),
            methods: {
                open() {
                    this.drawer = true;
                },
                close() {
                    this.drawer = false;
                }
            }
        }
    </script>
    

    如您所见,您可以使用 ref 访问子方法(和状态值)。 更多关于参考here。 你也可以使用emit来做到这一点,如果你需要在父组件中保留drawer属性,你可以阅读here

    【讨论】:

    • 这很好用 :),谢谢 @Asi Ple 兄弟
    猜你喜欢
    • 2017-03-27
    • 2021-09-05
    • 2017-11-28
    • 2021-03-02
    • 2022-11-02
    • 2017-07-20
    • 2017-05-04
    • 2021-08-12
    • 2020-05-21
    相关资源
    最近更新 更多