vue3 setup 组合式api props父子组件传值详解

Vue3中,父组件通过v-bind向子组件传递数据,子组件通过defineProps定义接收。在setup中使用这些数据需先定义变量。为了保持响应式,需要使用toRefs将props转换,避免直接解构失去响应性。响应式依赖于ref或reactive的set方法,未通过它们修改数据则不会触发响应式更新。
摘要由CSDN通过智能技术生成

基本使用

vue3组合式api中 父组件通过在子组件上通过v-bind传递给子组件数据

<template>
  <div>
    <ChildComponent :message="parentMessage" />
  </div>
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const parentMessage = ref('Hello from Parent');
</script>

子组件通过defineprops函数在子组件中定义父组件中传入子组件的数据就可以接收这些数据,然后可在template中直接使用

<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script setup>
defineProps({
  message: {
    type: String,
    required: true
  }
});
</script>

但是想要在setup中使用父组件传递的数据时,必须定义变量接收defineprops的返回值才能使用

<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script setup>
const props = defineProps({
  message: {
    type: String,
    required: true
  }
});
console.log(props.message)
</script>

如果不定义一个变量接受,直接取data是undefinded

解构赋值

为了方便使用父组件的值,子组件一般会直接解构拿到父组件传下来的值(为了方便演示,我加了一个message2)

<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script setup>
const {message,message2} = defineProps({
  message: {
    type: String,
    required: true
  },
  message2: {
    type: String,
    required: true
  }
});
</script>

这样做可以直接使用data和data2,无需props.data

在Vue 3的组合式API中, defineProps 是一个内置的全局函数,不需要显式引入,而toRefs的使用需要引入。

toRefs

toRefs可以让一个reactive对象的属性都变为ref对象。在vue3早期版本时,解构props会造成数据会失去响应式,所以解构时,需要用torefs包裹,因为props本质上时reactive对象,torefs可以把reactive的每个属性变成ref对象,这样解构出来依旧是响应式。

<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script setup>
import {toRefs } from 'vue';

const props = defineProps({
  message: {
    type: String,
    required: true
  },
  message2: {
    type: String,
    required: true
  }
});
const {message,message2} = toRefs(props);
console.log(message,message2);
</script>

注意:torefs不能直接包裹defineprops函数,会报错defineprops未定义

通过ref响应式变量,修改对象本身不会触发响应式

还有一个因为响应式原理引发的有趣现象,首先我们定义一个obj对象,然后定义另一个obj1 ref对象包裹obj,如下图

<template>
  {{ obj1 }}
  <button
    @click="
      () => {
        obj.a = 3;
        console.log(obj, obj1);
      }
    "
  >
    123
  </button>
</template>
<script setup>
import { ref } from "vue";
const obj = { a: 1, b: 2 };
const obj1 = ref(obj);
</script>
<style></style>

此时通过obj更改对象内属性a ,可以看到无论是obj还是obj1都被成功更改,但dom并没有响应式更新,原因就是通过obj更改,并没有调用obj1的set方法,所以没有触发该实例的渲染函数,普通类型的数据也是一样,只要不是通过ref对象本身更改,都不会调用set方法,就不会调用组件实例渲染函数,也就不会响应式(想了解更多的响应式知识可以看我的另一篇文章响应式原理详解所以一般这种情况,需要其他变量定义响应式变量时,可以通过computed函数,即可响应式(ref包裹对象时,本质还是通过reactive包裹,所以一样会深度监听,所以没有响应式的原因就是没有调用set方法,跟ref能否深度监听无关)

用torefs包裹reactive对象会使其每个属性值都变成ref对象,单独具有响应式,所以结构出来不会失去响应式,但此ref对象和普通的ref对象不同,有两个普通ref对象没有的key属性和object属性,其中key属性是解构出来的属性的属性名,object是原reactive对象,当我们获取value值时,ref的get属性并不会直接返回value,而是通过key值向object属性值,也就是原reactive对象上获取,同样的,set方法也是更改原reactive对象,所以即使解构出来,单独使用,也会和原对象的值保持一致

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不止会JS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值