MeWrite Docs

[Vue warn]: Avoid mutating a prop directly

Vueで親から受け取ったpropsを直接変更しようとした際の警告

概要

Vue.jsで親コンポーネントから渡されたpropsを子コンポーネント内で直接変更しようとした際に発生する警告です。Vueは単方向データフローを採用しており、propsは読み取り専用です。

エラーメッセージ

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders.
Instead, use a data or computed property based on the prop's value.

原因

  1. propsへの直接代入: this.propName = newValue
  2. オブジェクト/配列の変更: propsで渡されたオブジェクトのプロパティを変更
  3. v-modelの誤用: propsに直接v-modelをバインド
  4. 単方向データフローの誤解: 親→子の流れを子→親で変更しようとする

解決策

1. ローカルのdataにコピー

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<template>
  <input v-model="localValue" />
</template>

<script setup>
import { ref, watch } from 'vue'

const props = defineProps({
  initialValue: String
})

// propsの初期値をローカルにコピー
const localValue = ref(props.initialValue)

// propsの変更を監視(必要に応じて)
watch(() => props.initialValue, (newVal) => {
  localValue.value = newVal
})
</script>

2. emitで親に通知

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- 子コンポーネント -->
<template>
  <input :value="modelValue" @input="updateValue" />
</template>

<script setup>
defineProps({
  modelValue: String
})

const emit = defineEmits(['update:modelValue'])

const updateValue = (event) => {
  emit('update:modelValue', event.target.value)
}
</script>

<!-- 親コンポーネント -->
<template>
  <ChildComponent v-model="parentValue" />
</template>

3. computedでget/set

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<template>
  <input v-model="computedValue" />
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({
  modelValue: String
})

const emit = defineEmits(['update:modelValue'])

const computedValue = computed({
  get: () => props.modelValue,
  set: (value) => emit('update:modelValue', value)
})
</script>

4. オブジェクトの場合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<script setup>
const props = defineProps({
  user: Object
})

const emit = defineEmits(['update:user'])

// Bad: propsのオブジェクトを直接変更
// props.user.name = 'New Name'

// Good: 新しいオブジェクトを作成してemit
const updateName = (newName) => {
  emit('update:user', { ...props.user, name: newName })
}
</script>

5. 配列の場合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<script setup>
const props = defineProps({
  items: Array
})

const emit = defineEmits(['update:items'])

// Bad: propsの配列を直接変更
// props.items.push(newItem)

// Good: 新しい配列を作成してemit
const addItem = (newItem) => {
  emit('update:items', [...props.items, newItem])
}

const removeItem = (index) => {
  emit('update:items', props.items.filter((_, i) => i !== index))
}
</script>

6. defineModelを使用(Vue 3.4+)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<!-- 子コンポーネント -->
<template>
  <input v-model="model" />
</template>

<script setup>
// Vue 3.4以降
const model = defineModel()
</script>

<!-- 親コンポーネント -->
<template>
  <ChildComponent v-model="value" />
</template>

よくある間違い

  • propsで渡されたオブジェクトのネストしたプロパティを変更する(参照は同じなので変更は伝播するが非推奨)
  • 子から親への通信にpropsを使おうとする
  • v-model修飾子の使い方を誤る

関連エラー

参考リンク

Vue.js の他のエラー

最終更新: 2025-12-13