Vue3中ESLint报no-mutating-props错误是否为误报?
Vue3中v-model绑定prop子属性触发ESLint警告的原因分析
问题场景
在Vue3项目中,尝试用v-model绑定父组件props中objVehicle的engine_options属性时,ESLint抛出警告:
Unexpected mutation of "objVehicle" prop.eslint(vue/no-mutating-props)
尝试两种父组件写法都无法消除警告,需求是按需创建objVehicle的engineOptions属性,相关代码如下:
父组件代码1
<template> <div> <ChildComponent v-model:engineOptions="objVehicle.engine_options" @update:engineOptions="emit('update:objVehicle', objVehicle)" /> </div> </template> <script setup lang="ts"> import ChildComponent from "@....vue" const props = defineProps({ objVehicle: { type: Object, required: true, } }) const emit = defineEmits(['update:objVehicle']) </script>
父组件代码2
<template> <div> <ChildComponent v-model:objVehicle="objVehicle" @update:objVehicle="(event) => emit('update:objVehicle', event)" /> </div> </template> <script setup lang="ts"> import ChildComponent from "@....vue" const props = defineProps({ objVehicle: { type: Object, required: true, } }) const emit = defineEmits(['update:objVehicle']) </script>
子组件代码
<template>Form elements for the engineOptions property are placed here...</template> <script setup lang="ts"> const props = defineProps({ engineOptions: { type: Object, required: false, // create on-demand }, }) const emit = defineEmits(['update:engineOptions']) const initEngineOptions = async () => { if (!Array.isArray(props.engineOptions)) { emit('update:engineOptions', []) } } const engineOptions = computed({ get() { return props.engineOptions as TEngineOptions[] }, set(newVal: TEngineOptions[] | undefined) { emit('update:engineOptions ', newVal) }, }) // Remove self const atRemove = () => { engineOptions.value = undefined } </script>
警告并非误报,原因如下
ESLint的vue/no-mutating-props规则核心是禁止直接修改props本身或其引用类型的子属性,这是为了遵循Vue的单向数据流原则:props只能由父组件传递更新,子组件不能直接修改。
你的两种写法都触发了规则检测:
- 父组件1:
v-model:engineOptions="objVehicle.engine_options"本质是语法糖,展开后相当于:engineOptions="objVehicle.engine_options" @update:engineOptions="objVehicle.engine_options = $event",这里直接修改了objVehicle(父组件的props)的子属性engine_options,属于修改引用类型props的内部状态,违反单向数据流。后续的emit('update:objVehicle', objVehicle)只是把已经被修改的原props对象传回父组件,并没有解决直接修改props的问题。 - 父组件2:
v-model:objVehicle="objVehicle"直接把props对象绑定给子组件,子组件修改objVehicle的engineOptions属性时,同样是直接修改了父组件传入的props对象,触发规则警告。
解决方案:转成本地响应式对象处理
要解决这个问题,父组件需要先把props的objVehicle复制为本地的响应式对象,操作本地对象后再emit新的对象给父组件更新,避免直接修改props:
<template> <div> <ChildComponent v-model:engineOptions="localVehicle.engine_options" @update:engineOptions="handleUpdateEngine" /> </div> </template> <script setup lang="ts"> import ChildComponent from "@....vue" import { reactive } from 'vue' const props = defineProps({ objVehicle: { type: Object, required: true, } }) const emit = defineEmits(['update:objVehicle']) // 将props对象复制为本地响应式对象,避免直接修改props const localVehicle = reactive({ ...props.objVehicle }) const handleUpdateEngine = (newEngineOptions: TEngineOptions[] | undefined) => { localVehicle.engine_options = newEngineOptions // 传递新对象给父组件,而不是原props引用 emit('update:objVehicle', { ...localVehicle }) } </script>
这样修改后,所有对engine_options的操作都是基于本地响应式对象,不会直接修改父组件传入的props,ESLint的警告会自动消除,同时符合Vue的单向数据流规范。
内容的提问来源于stack exchange,提问作者svenema
相关产品推荐
相关产品推荐

