Vue 子組件修改 Props 值常見(jiàn)的錯(cuò)誤寫(xiě)法,你學(xué)會(huì)了嗎?
圖片
Vue 子組件修改props值常見(jiàn)的錯(cuò)誤寫(xiě)法
在 Vue 中,props 應(yīng)被視為只讀的,直接修改 props 會(huì)導(dǎo)致難以追蹤的 bug,并且違反了單向數(shù)據(jù)流的原則。
以下是一些常見(jiàn)的錯(cuò)誤寫(xiě)法及其解釋?zhuān)约罢_的處理方法。
1. 常見(jiàn)錯(cuò)誤寫(xiě)法
1.1. 直接修改 props
直接修改 props 是最常見(jiàn)的錯(cuò)誤之一。
這種做法會(huì)導(dǎo)致 Vue 控制臺(tái)輸出警告,并且可能會(huì)導(dǎo)致不可預(yù)測(cè)的行為。
<template>
<div>
<p>{{ title }}</p>
<button @click="updateTitle">Update Title</button>
</div>
</template>
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
title: String
});
const updateTitle = () => {
props.title = 'New Title'; // 錯(cuò)誤:直接修改 props
};
</script>
1.2. 使用 v-model 但未正確處理
雖然 v-model 可以實(shí)現(xiàn)雙向綁定,但如果使用不當(dāng),仍然會(huì)導(dǎo)致問(wèn)題。
<template>
<div>
<p>{{ title }}</p>
<input v-model="title"> <!-- 錯(cuò)誤:直接綁定到 props -->
</div>
</template>
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
title: String
});
</script>
1.3. 在 data 中直接使用 props
在 data 中直接使用 props 會(huì)導(dǎo)致數(shù)據(jù)的重復(fù)和不一致。
<template>
<div>
<p>{{ localTitle }}</p>
<button @click="updateTitle">Update Title</button>
</div>
</template>
<script setup>
import { ref, defineProps } from 'vue';
const props = defineProps({
title: String
});
const localTitle = ref(props.title); // 錯(cuò)誤:未處理 props 的變化
const updateTitle = () => {
localTitle.value = 'New Title';
};
</script>
2. 正確的處理方法
2.1. 使用局部狀態(tài)
在子組件中創(chuàng)建一個(gè)局部狀態(tài)來(lái)存儲(chǔ) prop 的值,并在需要時(shí)更新這個(gè)局部狀態(tài)。
使用 watch 來(lái)監(jiān)聽(tīng) prop 的變化。
<template>
<div>
<p>{{ localTitle }}</p>
<button @click="updateLocalTitle">Update Title</button>
</div>
</template>
<script setup>
import { ref, watch, defineProps } from 'vue';
const props = defineProps({
title: String
});
const localTitle = ref(props.title);
watch(() => props.title, (newVal) => {
localTitle.value = newVal;
});
const updateLocalTitle = () => {
localTitle.value = 'New Title';
};
</script>
2.2. 使用 $emit 發(fā)送事件
如果需要將子組件中的更改通知給父組件,可以使用 $emit 發(fā)送事件,讓父組件來(lái)更新數(shù)據(jù)。
2.2.1. 子組件
<template>
<div>
<p>{{ title }}</p>
<button @click="updateTitle">Update Title</button>
</div>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue';
const props = defineProps({
title: String
});
const emit = defineEmits(['update:title']);
const updateTitle = () => {
emit('update:title', 'New Title');
};
</script>
2.2.2. 父組件
<template>
<ChildComponent :title="title" @update:title="updateTitle" />
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const title = ref('Initial Title');
const updateTitle = (newTitle) => {
title.value = newTitle;
};
</script>
2.3. 使用計(jì)算屬性
如果需要基于 props 的值進(jìn)行一些計(jì)算,可以使用計(jì)算屬性來(lái)實(shí)現(xiàn)。
<template>
<div>
<p>{{ computedTitle }}</p>
</div>
</template>
<script setup>
import { defineProps, computed } from 'vue';
const props = defineProps({
title: String
});
const computedTitle = computed(() => {
return `Modified: ${props.title}`;
});
</script>
2.4. 使用 v-model 或自定義模型
Vue 3 支持 v-model 的自定義修飾符,可以更方便地實(shí)現(xiàn)雙向綁定。
2.4.1. 子組件
<template>
<div>
<p>{{ title }}</p>
<input v-model="localTitle" @input="onInput">
</div>
</template>
<script setup>
import { defineProps, defineEmits, computed } from 'vue';
const props = defineProps({
modelValue: String
});
const emit = defineEmits(['update:modelValue']);
const localTitle = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value)
});
const onInput = (event) => {
emit('update:modelValue', event.target.value);
};
</script>
2.4.2. 父組件
<template>
<ChildComponent v-model:title="title" />
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const title = ref('Initial Title');
</script>
3. 總結(jié)
- 直接修改 props:會(huì)導(dǎo)致 Vue 控制臺(tái)警告和不可預(yù)測(cè)的行為。
- 使用 v-model 但未正確處理:可能導(dǎo)致數(shù)據(jù)綁定錯(cuò)誤。
- 在 data 中直接使用 props:導(dǎo)致數(shù)據(jù)的重復(fù)和不一致。
通過(guò)使用局部狀態(tài)、發(fā)送事件、計(jì)算屬性或自定義模型,可以在不直接修改 props 的情況下,實(shí)現(xiàn)所需的功能,同時(shí)保持組件的可維護(hù)性和可預(yù)測(cè)性。