Vue 子組件修改 Props 值常見的錯誤寫法,你學會了嗎?
圖片
Vue 子組件修改props值常見的錯誤寫法
在 Vue 中,props 應被視為只讀的,直接修改 props 會導致難以追蹤的 bug,并且違反了單向數據流的原則。
以下是一些常見的錯誤寫法及其解釋,以及正確的處理方法。
1. 常見錯誤寫法
1.1. 直接修改 props
直接修改 props 是最常見的錯誤之一。
這種做法會導致 Vue 控制臺輸出警告,并且可能會導致不可預測的行為。
<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'; // 錯誤:直接修改 props
};
</script>
1.2. 使用 v-model 但未正確處理
雖然 v-model 可以實現雙向綁定,但如果使用不當,仍然會導致問題。
<template>
<div>
<p>{{ title }}</p>
<input v-model="title"> <!-- 錯誤:直接綁定到 props -->
</div>
</template>
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
title: String
});
</script>
1.3. 在 data 中直接使用 props
在 data 中直接使用 props 會導致數據的重復和不一致。
<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); // 錯誤:未處理 props 的變化
const updateTitle = () => {
localTitle.value = 'New Title';
};
</script>
2. 正確的處理方法
2.1. 使用局部狀態
在子組件中創建一個局部狀態來存儲 prop 的值,并在需要時更新這個局部狀態。
使用 watch 來監聽 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 發送事件
如果需要將子組件中的更改通知給父組件,可以使用 $emit 發送事件,讓父組件來更新數據。
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. 使用計算屬性
如果需要基于 props 的值進行一些計算,可以使用計算屬性來實現。
<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 的自定義修飾符,可以更方便地實現雙向綁定。
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. 總結
- 直接修改 props:會導致 Vue 控制臺警告和不可預測的行為。
- 使用 v-model 但未正確處理:可能導致數據綁定錯誤。
- 在 data 中直接使用 props:導致數據的重復和不一致。
通過使用局部狀態、發送事件、計算屬性或自定義模型,可以在不直接修改 props 的情況下,實現所需的功能,同時保持組件的可維護性和可預測性。