Unexpected mutation of “xxxx“ prop问题

问题:Unexpected mutation of "xxxx" prop

在接手别人的代码时,发现代码其中一个组件报错:Unexpected mutation of "xxxx" prop

  <el-col :md="6" v-for="(item, index) in queryFormArr" :key="index">
    <el-input
      v-model.trim="item.val"
      class="font-xs item-form-doc"
      v-if="item.type == 'number'"
      @input="inputCode(item.val, index)"
    ></el-input>
  </el-col>
  
  props: ['queryArr', 'flag'],
  watch: {
    queryArr: {
      // 筛掉label为空的
      handler(list) {
        if (!list) return
        this.queryFormArr = list.filter(item => item.label)
      },
      immediate: true,
      deep: true
    }
  },
  methods: {
    inputCode(val, index) {
      if (!this.game_reg.test(val)) {
        // 提示:Unexpected mutation of "queryArr" prop.
        this.queryArr[index].val = '' 
      }
    }
   }

分析

该错误由Eslint插件提醒,产生原因是由于在该组件内,修改了父组件传来的props值queryArr。

我们都知道,对于父传子的props值,是不允许在子组件内直接修改的。

一般如果我们需要修改传递来的props值,通常有两个做法比较方便:

1. 在子组件内定义新变量承接props值,对新变量进行各种赋值或修改操作达到交互效果,原本的这个props值咱们就放在那不动它。

2. 在子组件内通过emit方法,把要修改的queryArr新值通过emit传递给父组件,让父组件在其内部进行修改,而不是在子组件内直接对props值操作。

 props: ['queryArr', 'flag'],
  watch: {
    queryArr: {
      // 筛掉label为空的
      handler(list) {
        if (!list) return
        this.queryFormArr = list.filter(item => item.label)
      },
      immediate: true,
      deep: true
    }
  },
  methods: {
    inputCode(val, index) {
      if (!this.game_reg.test(val)) {
        // Eslint提示:Unexpected mutation of "queryArr" prop.
        this.queryArr[index].val = '' 
      }
    }
   }

那么这里我还有一个疑问:

        既然我们知道在Vue的单向传递流机制中,不允许子组件直接修改props值,为什么在这里明明修改了,还生效了,仅仅是Eslint插件检测到这种错误写法,而控制台没有任何报错,交互效果也能正常实现呢?

这里就涉及到修改的props值的类型区别了,请看以下代码:

 props: ['queryArr', 'flag'],
  watch: {
    queryArr: {
      // 筛掉label为空的
      handler(list) {
        if (!list) return
        this.queryFormArr = list.filter(item => item.label)
      },
      immediate: true,
      deep: true
    }
  },
  methods: {
    inputCode(val, index) {
      if (!this.game_reg.test(val)) {

        // 【修改props的queryArr】
        // Eslint提示:Unexpected mutation of "queryArr" prop.
        this.queryArr[index].val = '' 

        // 【修改props的flag】
        // TypeError: Cannot read properties of undefined (reading 'type')
        this.flag = 'newFlag'
      }
    }
   }

一种是改变引用类型的props,另一种是改变值类型的props。

在上述代码种可以看到,在改变queryArr时,值可以改变并在页面上生效;

而改变flag时,值不能被改变,并且控制台会报错。

这是因为,queryArr是一个引用数据类型,父组件传递来的queryArr只是一个引用,也就是传了一个内存地址(指针)。子组件改变的是queryArr上面的值,并没有改变这个指针,所以系统认为子组件没有引起父组件的值改变,于是就没有报错提示了。

解决

不管怎么说,我们需要解决这个Eslint的提醒,方法有如下三种:

1. 禁掉工作区的Eslint插件(不提倡)

        简单粗暴,但是不提倡,禁掉以后更麻烦了,原因不多说。

2. 修改'vue/no-mutating-props'

        Eslint插件官方对此给出说明:vue/no-mutating-props     

        'vue/no-mutating-props'是一个ESLint规则,默认值为false。

        它用于在Vue.js的单文件组件中禁止对props进行直接修改,确保props是只读的,以避免副作用和不可预知的行为。

        想要不让Eslint禁止你修改props值,具体做法是在ESLint 配置文件中加入以下配置:

// .eslintrc.cjs

module.exports = {
  ..........
  ..........
  rules: {
    // 加入以下配置,让Eslint允许你修改props值
    'vue/no-mutating-props': [
      'error',
      {
        shallowOnly: false  //默认值为true
      }
    ]
  }
}

3. 用新变量代替对props值的修改

其实在代码中可以看到,子组件内部是用了新变量queryFormArr来处理props.queryArr值的,不明白为何当初的开发者没有直接修改queryFormArr。

不管怎么说,用新变量代替props值去修改是更正确的做法。

若涉及到需要将修改后的新值传递回父组件,用emit触发即可。

  props: ['queryArr', 'flag'],
  watch: {
    queryArr: {
      // 筛掉label为空的
      handler(list) {
        if (!list) return
        this.queryFormArr = list.filter(item => item.label)
      },
      immediate: true,
      deep: true
    }
  },
  methods: {
    inputCode(val, index) {
      if (!this.game_reg.test(val)) {
        // 修改queryFormArr,而不是props值queryArr
        this.queryFormArr[index].val = '' 
      }
    }
   }

  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值