# 组合式api

整理碎片化逻辑,将统一逻辑整理在一起,方便对逻辑进行处理

# 核心setup(props,context)

# props

在setup中的props参数是接收组件传入属性

当props传入新的值时,setup中的值也会被更新,所以props是响应式的。
setup 执行时机是在 beforeCreate 之前执行

export default {
  props: {
    title: String
  },
  setup(props) {
    console.log(props.title)
  }
}

因为 props 是响应式的,你不能使用 ES6 解构,它会消除 prop 的响应性。

需要解构 prop,可以在 setup 函数中使用 toRefs 函数来完成

import { toRef } from 'vue'
setup(props) {
  const title = toRef(props, 'title')
  console.log(title.value)
}

# context

在setup中的context参数是接收组件传入的方法
context中就提供了三个属性:attrs、slot 和emit,分别对应 Vue2.x 中的 $attr属性、slot插槽 和$emit发射事件。并且这几个属性都是自动同步最新的值,所以我们每次使用拿到的都是最新值。

export default {
  setup(props, context) {
    // Attribute (非响应式对象,等同于 $attrs)
    console.log(context.attrs)

    // 插槽 (非响应式对象,等同于 $slots)
    console.log(context.slots)

    // 触发事件 (方法,等同于 $emit)
    console.log(context.emit)

    // 暴露公共 property (函数)
    console.log(context.expose)
  }
}

this的使用

在 setup() 内部,this 不是该活跃实例的引用,因为 setup() 是在解析其它组件选项之前被调用的,所以 setup() 内部的 this 的行为与其它选项中的 this 完全不同。这使得 setup() 在和其它选项式 API 一起使用时可能会导致混淆。

# 响应式声明值ref、reactive

两者之间的区别:在setup返回的refs在模版中访问时ref是自动浅解包,而reactive是深层解包。

好处:可维护性明显提高,可以控制哪些变量暴露,可以跟中哪些属性被定义 (属性继承与引用透明)

# reactive

对引用数据类型数据进行装箱操作使得成为一个响应式对象,可以跟踪数据变化。

const count = ref(1)
const obj = reactive({ count:count })

// ref 会被解包
console.log(obj.count === count.value) // true

// 它会更新 `obj.count`
count.value++
console.log(count.value) // 2
console.log(obj.count) // 2

// 它也会更新 `count` ref
obj.count++
console.log(obj.count) // 3
console.log(count.value) // 3

# isReactive

检查对象是否是由 reactive 创建的响应式代理。

# readonly

接受一个对象 (响应式或纯对象) 或 ref 并返回原始对象的只读代理。只读代理是深层的:任何被访问的嵌套 property 也是只读的。

const original = reactive({ count: 0 })

const copy = readonly(original)

watchEffect(() => {
  // 用于响应性追踪
  console.log(copy.count)
})

// 变更 original 会触发依赖于副本的侦听器
original.count++

// 变更副本将失败并导致警告

# shallowReactive

创建一个响应式代理,它跟踪其自身 property 的响应性,但不执行嵌套对象的深层响应式转换 (暴露原始值)。

const state = shallowReactive({
  foo: 1,
  nested: {
    bar: 2
  }
})

// 改变 state 本身的性质是响应式的
state.foo++
// ...但是不转换嵌套对象
isReactive(state.nested) // false
state.nested.bar++ // 非响应式

# ref

对基本数据类型数据进行装箱操作使得成为一个响应式对象,可以跟踪数据变化。
接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象具有指向内部值的单个 property .value。

# toRef

主要用于接收props参数时使用, 因为即使源 property 不存在,toRef 也会返回一个可用的 ref。这使得它在使用可选 prop 时特别有用,可选 prop 并不会被 toRefs 处理。

export default {
  setup(props) {
    useSomeFeature(toRef(props, 'foo'))
  }
}

# toRefs

将响应式对象转化为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 ref。 主要用于reactive解构使用

const state = reactive({
    foo: 1,
    bar: 2
  });

  const stateAsRefs = toRefs(state);

  // ref 和原始 property 已经“链接”起来了
  state.foo++;
  console.log(stateAsRefs.foo.value); // 2

  stateAsRefs.foo.value++;
  console.log(state.foo); // 3
  //  const { foo, bar } = stateAsRefs;
  const { foo, bar } = state;
  console.log(foo.value, bar.value);

# isRef

检查值是否为一个 ref 对象。

# 动态监听(computed,watch)

# computed计算属性

1、接受一个getter函数,并根据getter的返回值返回一个不可变的响应式ref对象。

  const count = ref(1)
  const plusOne = computed(() => count.value + 1)

  console.log(plusOne.value) // 2

  plusOne.value++ // 错误 :返回的是一个不可变的响应式ref对象

2、或者,接受一个具有 get 和 set 函数的对象,用来创建可写的 ref 对象。

  const count = ref(1);
  const plusOne = computed({
    get: () => count.value + 1,
    set: val => {
      count.value = val - 1;
    }
  });

  console.log(count.value); // 1 只是单纯的获取ref中count的值,未触发computed
  console.log(plusOne.value); // 2 获取computed属性值,触发get函数
  count.value = 2;
  console.log(plusOne.value); // 3 获取computed属性值,触发get函数,count.value=2,
  plusOne.value = 4;
  console.log(count.value); // 3 因为plusOne传入值,触发set函数,4-1=3。
  console.log(plusOne.value); // 4 当前count.value=3,获取计算属性触发get 3+1=4

3、在reactive中使用 computed

const date = reactive({ 
  dates:new Date(),
  timeData:computed(()=>{ 
    return date.dates
  }), 
  yearData:""
})
const {timeData, yearData} = toRefs(date)

return {
  timeData, yearData
}

# watch