← Debugging Guides

阅读中文版本

Vue: mutating a prop warning and one-way data flow

Fix the Vue avoid-mutating-prop warning by emitting events, using local state, and modelling one-way data flow correctly.

beginnerdebuggingvuepropsstate

Symptoms

  • Avoid mutating a prop directly since the value will be overwritten
  • A child component change is reverted on the next parent render
  • Vue 3 throws reading a read-only computed for a mutated prop

Possible causes

  • The child assigns to a prop instead of emitting an event
  • A parent object is mutated through a shared reference
  • The prop is used as v-model without an update handler
  • A watch writes back into the prop instead of emitting

Diagnosis steps

Locate the assignment to a prop inside the child

Interpretation

Direct assignment props.x = ... is the trigger; the parent owns the value.

Replace with an emit or local copy

Interpretation

Emitting an event or copying into local ref restores one-way flow.

For v-model, check the update event name

Interpretation

v-model requires the child to emit update:modelValue for the value to flow back.

Root cause

Vue enforces one-way data flow: a parent passes data down and the child communicates changes up through events. Mutating a prop breaks that contract because the parent will overwrite the value on its next render, and a child cannot own state it does not control. Deep mutation through a shared object reference is the same violation, one level removed.

Fix

Emit an event for changes the parent should apply, or copy the prop into local state when the child needs an editable buffer. Use v-model with the correct update event for two-way bindings, and avoid mutating objects received as props by cloning before change. Treat props as read-only inputs and lift shared state to the nearest common owner.

Verify the fix

Change the value in the child; no mutation warning appears, the parent applies the update through the emitted event, and the value persists across re-renders.

Symptoms

Vue logs a warning that a prop is being mutated, or a change made in a child silently reverts. In Vue 3 the prop object is read-only, so writes may throw.

Diagnosis

Find the assignment in the child:

// child.vue — do not do this
props.count++;

The parent owns count, so any write here is overwritten on the next render.

Fix

Emit the change, or keep a local copy:

// child.vue
const emit = defineEmits(['update:count']);
function increment() {
  emit('update:count', props.count + 1);
}

// or an editable local buffer
const local = ref(props.count);
<Child v-model:count="count" />

Verification

Increment in the child; no mutation warning appears and the parent value updates through the event. The value survives a re-render, confirming the flow is now parent-owned.

Additional Notes

Vue enforces one-way data flow so that ownership of state stays with the component that renders it, which is why a prop write is overwritten on the next parent render. Emitting an event keeps the parent authoritative and makes the change traceable, while a local copy suits a child that needs an editable buffer synchronised back only when appropriate. The same rule forbids mutating a shared object received as a prop, so cloning before change avoids surprising the parent, and using the correct model update event keeps two-way bindings working without violating the contract.