Vue中方法修改变量后子组件未更新问题排查
Vue子组件未随父组件props更新的问题分析与解决
场景与问题
父组件MyForm接收MyClass类的实例,克隆后传给Modification子组件用于用户修改,修改功能正常。但调用resetObject方法重置父组件的newObject后,newObject本身已变为新的实例且是响应式的(父组件模板中的{{ newObject.a }}和计算属性均能正常更新),但Modification组件却仍显示旧的修改值,内部也未检测到更新。
相关代码
父组件MyForm
<template> <v-card> <Modification v-model="newObject"></Modification> <OtherComponent @close="resetObject"></OtherComponent> </v-card> </template> <script> import { MyClass } from "classes"; import Modification from "b"; import OtherComponent from "a"; export default { name: "MyForm", components: { OtherComponent, Modification }, props: { existingObject: { type: [MyClass, typeof undefined], required: false, default: undefined } }, data() { return { newObject: undefined }; }, created() { this.newObject = this.existingObject !== undefined ? this.existingObject.clone() : new MyClass(); }, methods: { resetObject() { this.newObject = this.existingObject !== undefined ? this.existingObject.clone() : new MyClass(); } } }; </script>
MyClass类定义
export class MyClass { constructor({ a= null, b=null} = {}) { this.a = a; this.b = b; } toPayload(){ return { a:this.a , b:this.b }; } clone() { return new MyClass(this.toPayload()); } }
Modification子组件
<template> <v-card-text> <ModifyA v-model="object.a" @input="handleInput" /> <ModifyB v-model="object.b" @input="handleInput" /> </v-card-text> </template> <script> import { MyClass } from "classes"; import ModifyA from "..."; import ModifyB from "..."; export default { name: "ShiftFormFields", components: { ModifyA, ModifyB }, props: { value: { type: MyClass, required: true } }, data() { return { object: this.value }; }, methods: { handleInput() { this.$emit("input", this.object); } } }; </script>
问题原因
核心问题在Modification组件的初始化逻辑:
- 子组件的
data中的object仅在组件创建时赋值为this.value(父组件传入的初始实例)。 - 当父组件重置
newObject时,子组件的props.value会更新为新的MyClass实例,但子组件内部的object数据并不会自动同步——因为Vue的data不会主动监听props的变化来更新自身,除非显式设置监听。 - 输入框绑定的是子组件
data里的object.a和object.b,所以即使父组件的value变了,子组件用的还是旧的实例,自然显示旧值。
而直接在父组件使用ModifyA绑定newObject.a时,输入框直接绑定的是父组件响应式的newObject属性,所以重置后能正常更新。
解决方案
方案1:直接使用props的value,不存到data
去掉子组件中冗余的object数据,直接使用props.value,这样当父组件的newObject重置时,子组件的value会自动更新为新实例,输入框绑定的新实例属性自然同步:
<template> <v-card-text> <ModifyA v-model="value.a" @input="handleInput" /> <ModifyB v-model="value.b" @input="handleInput" /> </v-card-text> </template> <script> import { MyClass } from "classes"; import ModifyA from "..."; import ModifyB from "..."; export default { name: "ShiftFormFields", components: { ModifyA, ModifyB }, props: { value: { type: MyClass, required: true } }, methods: { handleInput() { this.$emit("input", this.value); } } }; </script>
方案2:监听props变化,同步更新data中的object
如果子组件必须保留object数据(比如有内部状态管理需求),添加watch监听value的变化,主动更新object:
<template> <v-card-text> <ModifyA v-model="object.a" @input="handleInput" /> <ModifyB v-model="object.b" @input="handleInput" /> </v-card-text> </template> <script> import { MyClass } from "classes"; import ModifyA from "..."; import ModifyB from "..."; export default { name: "ShiftFormFields", components: { ModifyA, ModifyB }, props: { value: { type: MyClass, required: true } }, data() { return { object: this.value }; }, watch: { // 监听value变化,同步更新object value(newVal) { this.object = newVal; } }, methods: { handleInput() { this.$emit("input", this.object); } } }; </script>
内容的提问来源于stack exchange,提问作者Chgad
相关产品推荐
相关产品推荐

