Vue 3 删除组件道具反应性
Vue 3 remove component prop reactivity
我有 EditTransaction 组件并像这样调用它:
<edit-transaction
v-if="editableTransaction.id === transaction.id"
:key="'transaction'+transaction.id+etcount"
:class="{'bg-red-300': type === 'expense', 'bg-green-300': type === 'income'}"
:groups-prop="modelValue"
:transaction="transaction"
class="planning-transactions-item px-10 rounded-2xl w-[90%]"
@close="editableTransaction = {id: null}">
</edit-transaction>
如您所见,我在其中发送了一个交易对象。由于这是一个编辑器,我不希望事务对象是反应性的。如果有人关闭了编辑器,我想要原始的事务对象而不是一些修改过的对象,所以如果我是正确的并且想删除代理我把它放在编辑器中:
const form = toRaw(props.transaction)
在编辑器模板中,有一些资产组件,其 v-model 值绑定到表单对象
<div class="flex gap-5 w-full">
<FormInput id="et-date" v-model="form.due_date" class="et-fields tw-fields w-[150px]"
placeholder="Date"
type="date"
@keyup.enter="saveChanges"></FormInput>
<FormInput id="et-name" v-model="form.name" class="et-fields tw-fields" placeholder="Name"
@keyup.enter="saveChanges"></FormInput>
<FormInput id="et-value" v-model="form.value" class="et-fields tw-fields" mask-thousand
placeholder="Value"
@keyup.enter="saveChanges"></FormInput>
</div>
问题是,当我更改事务名称时,表单对象会更改,但事务属性也会更改。因此,名称也会在父数据中更改,因为交易道具是反应性的。
我做错了什么或者我怎样才能拥有一个表单对象,该表单对象的值在组件创建时用 props 值填充并且没有任何代理?
使用道具将初始值传递给子组件的状态是很常见的。这意味着您在本地 data
中“复制”了一个 prop 的值。它使 prop 值免受意外更改的影响:Read more in Vue docs
这是一个非常简单的示例,展示了上述方法:
/your-child-component-vue/
export default {
props: ['initialCounter'],
data() {
return {
// counter only uses this.initialCounter as the initial value;
// it is disconnected from future prop updates.
counter: this.initialCounter
}
}
}
现在,阅读您的示例,我发现您正在尝试更新表单中的一些数据,并且您不想更改初始信息,除非通过按钮或其他方式确认。解决这个问题的流程是:
- 将用户可能更改的初始数据作为道具传递。
- 如果用户通过输入元素更改了一些数据但没有确认这些更改(通过按钮)保持数据不变(这意味着您不会向父级发送任何更改,保持道具值不变)
- 如果用户更改了一些数据并进行了确认,则将此更新后的数据发送给父级 (
this.$emit
),以便它知道这些更改。
所以我找到了两个解决方案:
const form = reactive({...props.transaction})
或
const form = Object.assign({}, props.transaction)
两者都有效,而且当我更改表单值时,它不会改变 prop。
我有 EditTransaction 组件并像这样调用它:
<edit-transaction
v-if="editableTransaction.id === transaction.id"
:key="'transaction'+transaction.id+etcount"
:class="{'bg-red-300': type === 'expense', 'bg-green-300': type === 'income'}"
:groups-prop="modelValue"
:transaction="transaction"
class="planning-transactions-item px-10 rounded-2xl w-[90%]"
@close="editableTransaction = {id: null}">
</edit-transaction>
如您所见,我在其中发送了一个交易对象。由于这是一个编辑器,我不希望事务对象是反应性的。如果有人关闭了编辑器,我想要原始的事务对象而不是一些修改过的对象,所以如果我是正确的并且想删除代理我把它放在编辑器中:
const form = toRaw(props.transaction)
在编辑器模板中,有一些资产组件,其 v-model 值绑定到表单对象
<div class="flex gap-5 w-full">
<FormInput id="et-date" v-model="form.due_date" class="et-fields tw-fields w-[150px]"
placeholder="Date"
type="date"
@keyup.enter="saveChanges"></FormInput>
<FormInput id="et-name" v-model="form.name" class="et-fields tw-fields" placeholder="Name"
@keyup.enter="saveChanges"></FormInput>
<FormInput id="et-value" v-model="form.value" class="et-fields tw-fields" mask-thousand
placeholder="Value"
@keyup.enter="saveChanges"></FormInput>
</div>
问题是,当我更改事务名称时,表单对象会更改,但事务属性也会更改。因此,名称也会在父数据中更改,因为交易道具是反应性的。 我做错了什么或者我怎样才能拥有一个表单对象,该表单对象的值在组件创建时用 props 值填充并且没有任何代理?
使用道具将初始值传递给子组件的状态是很常见的。这意味着您在本地 data
中“复制”了一个 prop 的值。它使 prop 值免受意外更改的影响:Read more in Vue docs
这是一个非常简单的示例,展示了上述方法:
/your-child-component-vue/
export default {
props: ['initialCounter'],
data() {
return {
// counter only uses this.initialCounter as the initial value;
// it is disconnected from future prop updates.
counter: this.initialCounter
}
}
}
现在,阅读您的示例,我发现您正在尝试更新表单中的一些数据,并且您不想更改初始信息,除非通过按钮或其他方式确认。解决这个问题的流程是:
- 将用户可能更改的初始数据作为道具传递。
- 如果用户通过输入元素更改了一些数据但没有确认这些更改(通过按钮)保持数据不变(这意味着您不会向父级发送任何更改,保持道具值不变)
- 如果用户更改了一些数据并进行了确认,则将此更新后的数据发送给父级 (
this.$emit
),以便它知道这些更改。
所以我找到了两个解决方案:
const form = reactive({...props.transaction})
或
const form = Object.assign({}, props.transaction)
两者都有效,而且当我更改表单值时,它不会改变 prop。