Vueでは、propは親コンポーネントから子コンポーネントに渡されるプロパティを受け取ることができますが、propを変更することはできません。
プロップが強制的に変更された場合の警告
❝[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.
❞
もちろん、上記で混乱した場合は、Propに関する公式サイトのドキュメントをチェックすることができます。
1.親子コンポーネントを使用した値の変更
上記の警告は、おそらく、子コンポーネントの値だけを変更しても、親コンポーネントが再レンダリングされて更新されたときに同じ値が渡され、書き換えの状況が発生することを意味します。
わかりやすく言うと、どのコンポーネントが値を定義するかは、どのコンポーネントがメソッドを定義するかによって変更されるべきです。
Vuexのステート管理と同様に、ステートの値がミューテーション操作によってのみ変更できる理由の核心は、トレーサビリティです。
唯一の "管理者 "は、それが "乱雑 "にならないように、変更操作を実行するために、複数の異なるIDを避けるために、変更操作を実行するために、トレーサビリティの状態である限り、それは一目で明確になるように、操作を行うには変異として。
当然、子コンポーネントに渡されるpropのデータが親コンポーネントで定義されていれば、propのデータを変更するメソッドは親コンポーネントで定義することができます。
<!--親コンポーネント>
<template>
<div>
<Child :propNum="num" @propFun="changeNum"/>
</div>
</template>
<script>
// src/components/Childを導入する
// ファイルディレクトリに応じて変更されるように導入された
import Child from '@/components/Child'
export default {
components: { // 登録されたコンポーネント
Child
},
data () {
return { // num値を定義する
num: 0
}
},
methods: { // 値を変更するメソッドを定義する
changeNum () {
this.num = this.num + 1
}
}
}
</script>
<!--サブコンポーネント>
<template>
<div>
<span>
{{propNum}}
</span>
<button type="button" @click="onClick">
add
</button>
</div>
</template>
<script>
export default {
props: {
propNum: { // 親と子のコンポーネントによって渡されるプロパティを受け入れる
type: Number,
default: 0
}
},
methods: {
onClick () { // ボタンのトリガーをクリックすると、親コンポーネントは、子コンポーネントにメソッドを渡す。
this.$emit('propFun')
}
}
}
</script>
.sync
以下は、上記と同様の例です。
<!--親コンポーネント>
<template>
<div>
<Child :propNum.sync="num"/>
</div>
</template>
<script>
// src/components/Childを導入する
// ファイルディレクトリに応じて変更されるように導入された
import Child from '@/components/Child'
export default {
components: {
Child
},
data () {
return {
num: 0
}
}
}
</script>
<!--サブコンポーネント>
<template>
<div>
<span>
{{propNum}}
</span>
<button type="button" @click="onClick">
add
</button>
</div>
</template>
<script>
export default {
props: {
propNum: {
type: Number,
default: 0
}
},
methods: {
onClick () {
const num = this.propNum + 1 // num値を定義する
this.$emit('update:propNum', num) // 更新された値を渡す
}
}
}
</script>
3. カスタムコンポーネントを使用したVモデル
v-modeをカプセル化するvueとは異なり、以下ではカスタム・コンポーネントのv-modelを使用します。
<!--親コンポーネント>
<template>
<div>
<Child v-model="num"/>
</div>
</template>
<script>
// src/components/Childを導入する
// ファイルディレクトリに応じて変更されるように導入された
import Child from '@/components/Child'
export default {
components: {
Child
},
data () {
return {
num: 0
}
}
}
</script>
<!--サブコンポーネント>
<template>
<div>
<span>
{{propNum}}
</span>
<button type="button" @click="onClick">
add
</button>
</div>
</template>
<script>
export default {
model: {
prop: 'propNum', // v-modelプロップで渡される名前を選択する
event: 'changeNum' // イベントを定義する
},
props: {
propNum: {
type: Number,
default: 0
}
},
methods: {
onClick () {
const num = this.propNum + 1
this.$emit('changeNum', num) // $emitイベントをトリガし、値を渡す
}
}
}
</script>
要約
上記の3つのメソッドはすべてpropsを「偽装」することができ、親子コンポーネントを使用して値を渡すことは「状態を定義しながら、状態を変更するメソッドを定義する」ことを指しており、最後の2つ、.syncとv-modelはsyncとv-modelは「双方向バインディング」を使用しています。
最初の2つは理解できそうですが、最後の2つはどうやって確認するのでしょうか?それは、.syncモディファイアとwatchを使うように、親と子のコンポーネントにwatchを使えばいいのです:
<!--親コンポーネント>
<template>
<div>
<Child :propNum.sync="num"/>
</div>
</template>
<script>
// src/components/Childを導入する
// ファイルディレクトリに応じて変更されるように導入された
import Child from '@/components/Child'
export default {
components: {
Child
},
data () {
return {
num: 0
}
},
watch: { // 親コンポーネントのnumプロパティに耳を傾ける
num: {
handler () {
console.log('親コンポーネントnum', this.num)
}
}
}
}
</script>
<!--サブコンポーネント>
<template>
<div>
<span>
{{propNum}}
</span>
<button type="button" @click="onClick">
add
</button>
</div>
</template>
<script>
export default {
props: {
propNum: {
type: Number,
default: 0
}
},
methods: {
onClick () {
const num = this.propNum + 1 // num値を定義する
this.$emit('update:propNum', num) // 更新された値を渡す
}
},
watch: { // 子コンポーネントのpropNumプロパティに耳を傾ける
propNum: {
handler () {
console.log('サブコンポーネントpropNum', this.propNum)
}
}
}
}
</script>
実行し、追加ボタンをクリックすると、次のような結果が得られます。
カスタムコンポーネントの使用に似ていますが、Vモデルは、また、検証のこの方法を使用することができます、あなたは自分自身を確認することができ、〜を繰り返すことはありません!
お読みいただきありがとうございました。