父组件
<template>
<button @click="add">父组件(点击+1)</button>
<div>得到的结果{{ res }}</div>
<subComponent :res="res" :obj="arr[0]"></subComponent>
</template>
<script setup>
import { ref } from 'vue';
import subComponent from './subComponent.vue'
let res = ref(1)
let arr = ref([
{ id: 1, name: 'one', value: 100 }
])
function add() {
res.value++
arr.value[0].value += 100
}
</script>
<style scoped></style>
子组件
<template>
<div>子组件</div>
<div>得到的结果为{{ newRes }}</div>
<div>得到的结果为{{ newObj }}</div>
<div>使用props直接在插值表达式中使用:{{ props.res }}</div>
</template>
<script setup>
import { ref, computed, toRefs } from 'vue';
const props = defineProps({
res: {
type: Number,
default: 0
},
obj: {
type: Object,
default: {}
}
})
// let { res } = toRefs(props)
//let newRes = ref(props.res)//直接将props中的值赋值给变量,就算使用了ref也不鞥保持响应式。因为此时只是将props中传递过来的值作为初始值
// 解决方式1:通过计算属性得到props中的值
/* let newRes = computed(() => {
return props.res
})
*/
/* let newObj = computed(() => {
return props.obj
}) */
// 解决方式2:使用toRefs
let { res } = toRefs(props)
let { obj } = toRefs(props)
let newRes = ref(res)//setup中内容只会执行一次,这里newRes还能保持响应式是因为newRes和res都指向了同一地址
let newObj = ref(obj)
</script>
<style scoped></style>
总结:如果不对子组件接收到的props进行toRefs,那么props整个变量还是响应式,因为官网中提到“所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。另外,每次父组件更新后,所有的子组件中的 props 都会被更新到最新值,这意味着你不应该在子组件中去更改一个 prop。若你这么做了,Vue 会在控制台上向你抛出警告”。如果要是用props.属性名时,在插值表达式中使用还是会保持响应式,在setup函数中使用会丢失响应式,希望在setup函数中保持响应式,需要将props进行toRefs,或者我们将需要的值通过计算属性从props中拿出来。还有一种方式是在onUpdated将我们想要的值赋值给响应式变量如下。
onUpdated(() => {
console.log(123);
newRes.value = props.res
})
let newRes = ref(props.res)