# 组合式 API

# setup

  1. Vue3 的一个新的配置项,其值为一个函数,此函数会在组件 init 时调用,其返回值会挂载在组件对象上。
  2. 原本的数据属性和方法就在setup中定义,并通过return返回出来
  3. 其返回值可以是一个对象,也可以是一个渲染函数
  4. 不建议混用 setup 和 Vue2 的 option API

注意

setup 不能是 async 函数,否则将返回一个 Promise

TIP

由于 setup 调用发生在 data 初始化之前,因此在 setup 函数中初始初始化时,不能访问 option 中的属性和方法

返回一个对象的形式

<template>
  <h1>个人信息</h1>
  <h3>姓名:{{ name }}</h3>
  <h3>年龄:{{ age }}</h3>
  <button @click="sayHello">Hello</button>
</template>

<script>
export default {
  name: "App",
  setup() {
    let name = "刘德华";
    let age = 18;
    function sayHello() {
      alert("Hello");
    }
    return {
      name,
      age,
      sayHello
    };
  }
};
</script>

返回一个渲染函数的形式

<script>
import { h } from "vue";
export default {
  name: "App",
  setup() {
    let name = "刘德华";
    let age = 18;
    function sayHello() {
      alert("Hello");
    }
    return () => {
      return h("div", [
        h("h1", {}, "个人信息"),
        h("h3", {}, "姓名:" + name),
        h("h3", {}, "年龄:" + age),
        h("button", { onClick: sayHello }, "Hello")
      ]);
    };
  }
};
</script>

# ref

ref非彼$refs

ref()用于包装一个简单数据类型,返回一个响应式的引用对象RefImpl

  • script xxx.value
  • template xxx

<template>
  <h1>Vue3</h1>
  <h2>{{ title }}</h2>
  <p>姓名:{{ user.name }}</p>
  <p>年龄:{{ user.age }}</p>
  <div v-for="(item, index) in hobbits" :key="index">{{ item }}</div>
  <button @click="changeAge">按钮</button>
</template>

<script lang="ts">
import { ref, reactive } from "vue";
export default {
  name: "App",
  setup() {
    let title = ref("前端工程师");
    let user = reactive({
      name: "Gauss Zhou",
      age: 18,
      a: {
        b: 1
      }
    });
    const hobbits = reactive(["吃饭", "睡觉", "打豆豆"]);
    console.log(title); // RefImpl
    console.log(title.value); // 前端工程师
    console.log(user); // Proxy {name: 'Gauss Zhou', age: 18}
    console.log(hobbits); // Proxy {0: '吃饭', 1: '睡觉', 2: '打豆豆'}
    function changeAge() {
      user.age++;
      console.log(user.age);
      console.log(user.a.b);
    }
    return {
      title,
      user,
      hobbits,
      changeAge
    };
  }
};
</script>
const foo = ref(1);
const bar = ref(foo)

console.log(foo === bar) // true

# reactive

reactive()用于包装一个对象或数组,返回一个响应式的代理对象Proxy

  • script xxx.a
  • template xxx.a

<script lang="ts" setup>
import { ref, reactive } from "vue";
interface User {
  name: string;
  age: number;
  a?: any;
}
let title = ref<string>("前端工程师");
let user = reactive<User>({
  name: "Gauss Zhou",
  age: 18
});
const hobbys = reactive<object>(["吃饭", "睡觉", "打豆豆"]);
console.log(title); // RefImpl
console.log(title.value);
console.log(user); // Proxy {name: 'Gauss Zhou', age: 18}
console.log(hobbys); // Proxy {0: '吃饭', 1: '睡觉', 2: '打豆豆'}
function changeAge() {
  user.age++;
  console.log(user.age);
}
</script>

<template>
  <h1>Vue3</h1>
  <h2>{{ title }}</h2>
  <p>姓名:{{ user.name }}</p>
  <p>年龄:{{ user.age }}</p>
  <div v-for="(item, index) in hobbys" :key="index">{{ item }}</div>
  <button @click="changeAge">按钮</button>
</template>

# ref vs reactive

从定义来说

  • ref 用于定义基本数据类型
  • reactive 用于定义引用数据类型

从实现来说

  • ref 使用 Object.defineProperty()
  • reactive 使用 Proxy 和 Reflect

从使用角度来说

  • ref 的值需要通过.value来访问

简单理解

function ref(val) {
  let value = val;
  let refImpl = Object.defineProperty("value", {
    get() {
      return value;
    },
    set(val) {
      value = val;
    }
  });
  return refImpl;
}