Vue3 组合式API.md

组合式API

介绍

什么是组合式 API(composition API)

  • 组合式 API 是 Vue3 提供的新功能,为我们提供了另一种编写组件的方式
  • 代码共享。在 setup 钩子里面,可以按逻辑上的关注点来对代码进行分组,并与其他组件共享代码。

组合式 API 的出现解决了什么样的问题

  • 随着Vue项目规模和复杂性的增加,现有 Option API 变得难以应付
  • 逻辑并没有真正地按功能分组,这可能会让人很难读懂一个庞大而复杂的组件文件。
  • 通过 Option API 实现组件间共享重复的逻辑(共享代码)比较麻烦
  • 通过组合时 API 我们可以将重用逻辑封装为功能,这个功能可以组件间共享,这样你就可以在整个应用程序的不同组件中使用这些逻辑。

接口

setup

执行时间

优先于beforeCreate 和 created。setup 选项在组件创建之前执行,一旦 props 被解析,就将作为组合式 API 的入口。

参数
  1. props:组件传入的属性
  2. context

setup中接受的props是响应式的,当传入新的props会被及时更新。在setup中不能直接访问到this对象。

所以在setup中定义props,用这样的方式

defineProps({
  msg: String
})

context是一个普通的JavaScript对象,它暴露组件的三个property
context.attrs, context.slots, context.emit

组合式API生命周期函数
组合式api生命周期

onBeforeMount
onMounted
onBeforeUpdate
onUpdated
onUnmounted ( -> destroyed)
onActivated ( -> activited)
onDeacitivated ( ->deacitivated)
onRenderTriggered
onRenderTricked

reactive 和 ref

reactive 和 ref的作用都是定义和跟踪需要双向绑定的变量。也就是数据定义,将一个普通对象变为响应式对象。

ref 接收参数并将其包裹在一个带有 value property 的对象中返回,然后可以使用该 property 访问或更改响应式变量的值

toRefs的作用就是,将一个reactive对象转化为属性全部为ref对象的普通对象

<template>
<div> {{ month }}</div>
</template>
<script>
import {ref,reactive,toRefs } from "vue"

export default defineComponent({
 setup() {
    const year = ref(0)
    const date = reactive({
        month: 1
        minutes:200
    })
    
    return {
        year,
        ...toRefs(date)
    }
 }
)
</script>


isRef

isRef用于判断变量是否为ref对象

const unwrapped = isRef(foo) ? foo.value : foo

computed

computed函数与vue2中computed功能一致,它接收一个函数并返回一个value为getter返回值的不可改变的响应式ref对象。

const count = ref(1)
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 2
plusOne.value++ // 错误,computed不可改变

// 同样支持set和get属性
onst count = ref(1)
const plusOne = computed({
  get: () => count.value + 1,
  set: val => { count.value = val - 1 }
})
plusOne.value = 1
console.log(count.value) // 0

watch

用法

  • 指定依赖源:
    在基础用法中,
    当依赖了多个reactive或ref是无法直接看到的,需要在回调中寻找.
<template>
  <div>
    <input type="text" v-model="state.count">{{state.count}}
    <input type="text" v-model="inputRef">{{inputRef}}
  </div>
</template>
<script>
  import {watch, reactive, ref} from 'vue'

  export default {
    setup() {
      const state = reactive({count: 0})
      const inputRef = ref('')
      // state.count与inputRef中任意一个源改变都会触发watch
      watch(() => {
        console.log('state', state.count)
        console.log('ref', inputRef.value)
      })
      return {state, inputRef}
    }
  }
</script>

  • 指定依赖源
<template>
  <div>
    state2.count: <input type="text" v-model="state2.count">
    {{state2.count}}<br/><br/>
    ref2: <input type="text" v-model="ref2">{{ref2}}<br/><br/>
  </div>
</template>
<script>
  import {watch, reactive, ref} from 'vue'

  export default {
    setup() {
      const state2 = reactive({count: ''})
      const ref2 = ref('')
      // 通过函数参数指定reative依赖源
      // 只有在state2.count改变时才会触发watch
      watch(
        () => state2.count,
        () => {
          console.log('state2.count',state2.count)
          console.log('ref2.value',ref2.value)
      })
      // 直接指定ref依赖源
      watch(ref2,() => {
        console.log('state2.count',state2.count)
        console.log('ref2.value',ref2.value)
      })

      return {state, inputRef, state2, ref2}
    }
  }
</script>

  • 指定多个数据源
<template>
  <div>
    <p>
      <input type="text" v-model="state.a"><br/><br/>
      <input type="text" v-model="state.b"><br/><br/>
    </p>
    <p>
      <input type="text" v-model="ref1"><br/><br/>
      <input type="text" v-model="ref2"><br/><br/>
    </p>
  </div>
</template>

<script>
  import {reactive, ref, watch} from 'vue'

  export default {
    setup() {
      const state = reactive({a: 'a', b: 'b'})
      // state.a和state.b任意一个改变都会触发watch的回调
      watch(() => [state.a, state.b],
       // 回调的第二个参数是对应上一个状态的值
       ([a, b], [preA, preB]) => {
        console.log('callback params:', a, b, preA, preB)
        console.log('state.a', state.a)
        console.log('state.b', state.b)
        console.log('****************')
      })

      const ref1 = ref(1)
      const ref2 = ref(2)
      watch([ref1, ref2],([val1, val2], [preVal1, preVal2]) => {
        console.log('callback params:', val1, val2, preVal1, preVal2)
        console.log('ref1.value:',ref1.value)
        console.log('ref2.value:',ref2.value)
         console.log('##############')
      })
      return {state, ref1, ref2}
    }
  }
</script>

  • 取消watch
<template>
  <div>
    <input type="text" v-model="inputRef">
    <button @click="onClick">stop</button>
  </div>
</template>

<script>
  import {watch, ref} from 'vue'

  export default {
    setup() {
      const inputRef = ref('')
      const stop = watch(() => {
        console.log('watch', inputRef.value)
      })
      const onClick = () => {
        // 取消watch,取消之后对应的watch不会再执行
        stop()
      }
      return {inputRef, onClick}
    }
  }
</script>

  • onCleanyp函数:watch提供了一个onCleanup的副作用清除函数,该函数接收一个函数,在该函数中进行副作用清除。那么onCleanup什么时候执行?

    • watch的callback即将被第二次执行时先执行onCleanup。
    • watch被停止时,即组件被卸载之后。
      -watch选项
  • deep
    深层对象的任意一个属性的改变都会出发回调的执行

<template>
  <div>
    <button @click="onClick">CHANGE</button>
  </div>
</template>
<script>
  import {watch, ref} from 'vue'

  export default {
    setup() {
      const objRef = ref({a: {b: 123}, c: 123})
      watch(objRef,() => {
        console.log('objRef.value.a.b',objRef.value.a.b)
      }, {deep: true})
      const onClick = () => {
        // 设置了deep之后,深层对象任意属性的改变都会触发watch回调的执行
        objRef.value.a.b = 780
      }
      return {onClick}
    }
  }
</script>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容