日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > vue >内容正文

vue

onmounted vue3_基于项目时间阐述vue3.0新型状态管理和逻辑复用方式

發(fā)布時(shí)間:2023/12/19 vue 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 onmounted vue3_基于项目时间阐述vue3.0新型状态管理和逻辑复用方式 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

作者:Mingle

轉(zhuǎn)發(fā)鏈接:https://mp.weixin.qq.com/s/iOq-eeyToDXJ6lvwnC12DQ

前言

背景:2019年2月6號(hào),React 發(fā)布 「16.8.0」 版本,vue緊隨其后,發(fā)布了「vue3.0 RFC」

Vue3.0受React16.0 推出的hook抄襲啟發(fā)(咳咳...),提供了一個(gè)全新的邏輯復(fù)用方案。使用基于函數(shù)的 API,我們可以將相關(guān)聯(lián)的代碼抽取到一個(gè) "composition function"(組合函數(shù))中 —— 該函數(shù)封裝了相關(guān)聯(lián)的邏輯,并將需要暴露給組件的狀態(tài)以相應(yīng)式的數(shù)據(jù)源的方式返回出來(lái)。

本文目的

本文會(huì)介紹Vue3.0「組合api的用法和注意點(diǎn)」。最后會(huì)用一個(gè) Todolist 的項(xiàng)目實(shí)戰(zhàn),向大家介紹「Vue3.0的邏輯復(fù)用寫(xiě)法以及借用provide和inject的新型狀態(tài)管理方式」

本文提綱:

  • 如何新建一個(gè)使用vue3.0的項(xiàng)目
  • conposition api
  • 邏輯復(fù)用(hook)和狀態(tài)管理(provide+inject)
    • 結(jié)合項(xiàng)目實(shí)戰(zhàn),做一個(gè)todo list

正文

如何新建一個(gè)使用vue3.0的項(xiàng)目

接下來(lái)向大家簡(jiǎn)單介紹下如何嘗鮮 -- 自己創(chuàng)建一個(gè)vue3.0的項(xiàng)目。

  • 安裝vue0-cli
  • 我這邊使用的是最新版本的vue-cli 4.4.0

    npm?install?-g?@vue/cli#?ORyarn?global?add?@vue/cli
  • 將vue升級(jí)到bata版本
  • vue?add?vue-next

    ok了。就這么簡(jiǎn)單!

    conposition api

    #### 目錄

    • 基本例子
    • setup()
    • reactive
    • ref
    • computed
    • watchEffect
    • watch
    • 生命周期
    • 依賴注入

    基本例子

    ??????count?is?{{?count.count?}}????plusOne?is?{{?plusOne?}}????count++??

    setup

    ?

    該setup功能是新的組件選項(xiàng)。它是組件內(nèi)部暴露出所有的屬性和方法的統(tǒng)一API。

    ?

    調(diào)用時(shí)機(jī)

    創(chuàng)建組件實(shí)例,然后初始化 props ,緊接著就調(diào)用setup 函數(shù)。從生命周期鉤子的視角來(lái)看,它會(huì)在 beforeCreate 鉤子之前被調(diào)用

    模板中使用

    如果 setup 返回一個(gè)對(duì)象,則對(duì)象的屬性將會(huì)被合并到組件模板的渲染上下文

    ??{{?count?}}?{{?object.foo?}}

    setup 參數(shù)

  • 「props」第一個(gè)參數(shù)接受一個(gè)響應(yīng)式的props,這個(gè)props指向的是外部的props。如果你沒(méi)有定義props選項(xiàng),setup中的第一個(gè)參數(shù)將為undifined。props和vue2.x并無(wú)什么不同,仍然遵循以前的原則;
    • 不要在子組件中修改props;如果你嘗試修改,將會(huì)給你警告甚至報(bào)錯(cuò)。
    • 不要結(jié)構(gòu)props。結(jié)構(gòu)的props會(huì)失去響應(yīng)性。

    2.「上下文對(duì)象」第二個(gè)參數(shù)提供了一個(gè)上下文對(duì)象,從原來(lái) 2.x 中 this 選擇性地暴露了一些 property。

    const?MyComponent?=?{??setup(props,?context)?{????context.attrs????context.slots????context.emit??},}

    Tip:

    由于vue3.x向下兼容vue2.x,所以我在嘗試之后發(fā)現(xiàn),一個(gè)vue文件中你可以同時(shí)寫(xiě)兩個(gè)版本的東西。

    import?{?reactive,?computed,?watch,?onMounted?}?from?'vue'export?default?{??name:?'HelloWorld',??props:?{????count:?Number,??},??data?()?{????return?{??????msg:?"我是vue2.x中的this"????}??},??methods:?{????test?()?{??????console.log(this.msg)????}??},??mounted?()?{????console.log('vue2.x?mounted')??},??//?eslint-disable-next-line?no-unused-vars??setup?(props,?val)?{????console.log(this,?'this')?//?undefined????onMounted(()?=>?{??????console.log('vue3.x?mounted')????})????return?{??????...props????}??}}

    當(dāng)然這邊不推薦你在項(xiàng)目中這么用,但是抱著嘗鮮和探究的態(tài)度,我們勢(shì)必要弄清如果這么寫(xiě)要注意哪些?

  • 如果我寫(xiě)了mounted(2.x),在setup函數(shù)中又寫(xiě)了onMounted(3.x),誰(shuí)先執(zhí)行?
  • setup中的先執(zhí)行。因?yàn)閟etup() 在解析 2.x 選項(xiàng)前被調(diào)用;

  • 我在vue2.x選項(xiàng)中中定義在this上的變量,在setup上可以通過(guò)this訪問(wèn)嗎?可以重復(fù)定義嗎?可以return嗎?
  • 首先在setup中的this將不再指向vue,而是undefined;所以在setup函數(shù)內(nèi)部自然無(wú)法訪問(wèn)到vue實(shí)例上的this。

    setup內(nèi)部定義的變量和外表的變量并無(wú)沖突;

    但是如果你要將其return 暴露給template,那么就會(huì)產(chǎn)生沖突。

    reactive

    ?

    接收一個(gè)普通對(duì)象然后返回該普通對(duì)象的響應(yīng)式代理。等同于 2.x 的 Vue.observable()

    ?

    const?obj?=?reactive({?count:?0?})

    ref

    ?

    接受一個(gè)參數(shù)值并返回一個(gè)響應(yīng)式且可改變的 ref 對(duì)象。ref 對(duì)象擁有一個(gè)指向內(nèi)部值的單一屬性 value。

    ?

    const?count?=?ref(0)console.log(count.value)?//?0count.value++console.log(count.value)?//?1

    tip:

  • ref常用于基本類型,reactive用于引用類型。如果ref傳入對(duì)象,其實(shí)內(nèi)部會(huì)自動(dòng)變?yōu)閞eactive.
  • 當(dāng) ref 作為渲染上下文的屬性返回(即在setup() 返回的對(duì)象中)并在模板中使用時(shí),它會(huì)自動(dòng)解套,無(wú)需在模板內(nèi)額外書(shū)寫(xiě) .value;
  • ??{{?count?}}
  • 當(dāng) ref 作為 reactive 對(duì)象的 property 被訪問(wèn)或修改時(shí),也將自動(dòng)解套 value 值,其行為類似普通屬性。
  • const?count?=?ref(0)const?state?=?reactive({??count,})console.log(state.count)?//?0state.count?=?1console.log(count.value)?//?1
  • 注意當(dāng)嵌套在 reactive Object 中時(shí),ref 才會(huì)解套。從 Array 或者 Map 等原生集合類中訪問(wèn) ref 時(shí),不會(huì)自動(dòng)解套:
  • const?arr?=?reactive([ref(0)])//?這里需要?.valueconsole.log(arr[0].value)const?map?=?reactive(new?Map([['foo',?ref(0)]]))//?這里需要?.valueconsole.log(map.get('foo').value)

    computed

    computed和vue2.x版本保持一致,支持getter和setter

    • 傳入一個(gè) getter 函數(shù),返回一個(gè)默認(rèn)不可手動(dòng)修改的 ref 對(duì)象。
    const?count?=?ref(1)const?plusOne?=?computed(()?=>?count.value?+?1)console.log(plusOne.value)?//?2plusOne.value++?//?錯(cuò)誤!
    • 或者傳入一個(gè)擁有 get 和 set 函數(shù)的對(duì)象,創(chuàng)建一個(gè)可手動(dòng)修改的計(jì)算狀態(tài)。
    const?count?=?ref(1)const?plusOne?=?computed({??get:?()?=>?count.value?+?1,??set:?(val)?=>?{????count.value?=?val?-?1??},})plusOne.value?=?1console.log(count.value)?//?0

    watchEffect

    ?

    傳入的一個(gè)函數(shù),并且立即執(zhí)行,響應(yīng)式追蹤其依賴,并在其依賴變更時(shí)重新運(yùn)行該函數(shù)。

    ?

    注冊(cè)監(jiān)聽(tīng)

    import?{watchEffect}from?'vue'?//?導(dǎo)入apiconst?count?=?ref(0)?//?定義響應(yīng)數(shù)據(jù)watchEffect(()?=>?console.log(count.value))?//?注冊(cè)監(jiān)聽(tīng)函數(shù)//?->?打印出?0setTimeout(()?=>?{??count.value++??//?->?打印出?1},?100)

    注銷監(jiān)聽(tīng)

    - 默認(rèn)情況下是在**組件卸載**的時(shí)候停止監(jiān)聽(tīng);- 也可以顯示**調(diào)用返回值**以停止偵聽(tīng);

    const?stop?=?watchEffect(()?=>?{??/*?...?*/})//?之后stop()

    清除副作用

    > 有時(shí)副作用函數(shù)會(huì)執(zhí)行一些異步的副作用, 這些響應(yīng)需要在其失效時(shí)清除(即完成之前狀態(tài)已改變了)。所以偵聽(tīng)副作用傳入的函數(shù)可以接收一個(gè) onInvalidate 函數(shù)作入?yún)? 用來(lái)注冊(cè)清理失效時(shí)的回調(diào)。

    當(dāng)以下情況發(fā)生時(shí),這個(gè)失效回調(diào)會(huì)被觸發(fā):

    • 副作用即將重新執(zhí)行時(shí)
    • 偵聽(tīng)器被停止
    const?count?=?ref(0)watchEffect(??(onInvalidate)?=>?{????console.log(count.value,?'副作用')???const?token?=??setTimeout(()?=>?{??????console.log(count.value,?'副作用')????},?4000)????onInvalidate(()?=>?{????//?id?改變時(shí)?或?停止偵聽(tīng)時(shí)????//?取消之前的異步操作????token.cancel()??})??})

    副作用刷新時(shí)機(jī)

    > Vue 的響應(yīng)式系統(tǒng)會(huì)緩存副作用函數(shù),并異步地刷新它們,這樣可以避免同一個(gè) tick 中多個(gè)狀態(tài)改變導(dǎo)致的不必要的重復(fù)調(diào)用。在核心的具體實(shí)現(xiàn)中, 組件的更新函數(shù)也是一個(gè)被偵聽(tīng)的副作用。當(dāng)一個(gè)用戶定義的副作用函數(shù)進(jìn)入隊(duì)列時(shí), 會(huì)在所有的組件更新后執(zhí)行:

    ??{{?count?}}

    在這個(gè)例子中:

    • count 會(huì)在初始運(yùn)行時(shí)同步打印出來(lái)
    • 更改 count 時(shí),將在組件更新后執(zhí)行副作用。

    如果副作用需要同步或在組件更新之前重新運(yùn)行,我們可以傳遞一個(gè)擁有 flush 屬性的對(duì)象作為選項(xiàng)(默認(rèn)為 'post'):

    //?同步運(yùn)行watchEffect(??()?=>?{????/*?...?*/??},??{????flush:?'sync',??})//?組件更新前執(zhí)行watchEffect(??()?=>?{????/*?...?*/??},??{????flush:?'pre',??})

    watch

    > watch API 完全等效于 2.x this.$watch (以及 watch 中相應(yīng)的選項(xiàng))。watch 需要偵聽(tīng)特定的數(shù)據(jù)源,并在回調(diào)函數(shù)中執(zhí)行副作用。默認(rèn)情況是懶執(zhí)行的,也就是說(shuō)僅在偵聽(tīng)的源變更時(shí)才執(zhí)行回調(diào)。

    • 對(duì)比 watchEffect,watch 允許我們:
      • 懶執(zhí)行副作用;
      • 更明確哪些狀態(tài)的改變會(huì)觸發(fā)偵聽(tīng)器重新運(yùn)行副作用;
      • 訪問(wèn)偵聽(tīng)狀態(tài)變化前后的值。
    • 偵聽(tīng)單個(gè)數(shù)據(jù)源

    偵聽(tīng)器的數(shù)據(jù)源可以是一個(gè)擁有返回值的 getter 函數(shù),也可以是 ref:

    //?偵聽(tīng)一個(gè)?getterconst?state?=?reactive({?count:?0?})watch(??()?=>?state.count,??(count,?prevCount)?=>?{????/*?...?*/??})//?直接偵聽(tīng)一個(gè)?refconst?count?=?ref(0)watch(count,?(count,?prevCount)?=>?{??/*?...?*/})
    • 偵聽(tīng)多個(gè)數(shù)據(jù)源
    watch([fooRef,?barRef],?([foo,?bar],?[prevFoo,?prevBar])?=>?{??/*?...?*/})
    • 與 watchEffect 共享的行為

    watch 和 watchEffect 在停止偵聽(tīng), 清除副作用 (相應(yīng)地 onInvalidate 會(huì)作為回調(diào)的第三個(gè)參數(shù)傳入),副作用刷新時(shí)機(jī) 和 助聽(tīng)器調(diào)試 等方面行為一致.

    生命周期鉤子函數(shù)

    ?

    可以直接導(dǎo)入 onXXX 一組的函數(shù)來(lái)注冊(cè)生命周期鉤子,這些生命周期鉤子注冊(cè)函數(shù)只能在 setup() 期間同步使用,在卸載組件時(shí),在生命周期鉤子內(nèi)部同步創(chuàng)建的偵聽(tīng)器和計(jì)算狀態(tài)也將自動(dòng)刪除。

    ?

    • 「與 2.x 版本生命周期相對(duì)應(yīng)的組合式 API」
      • beforeCreate -> 使用 setup()
      • created -> 使用 setup()
      • beforeMount -> onBeforeMount
      • mounted -> onMounted
      • beforeUpdate -> onBeforeUpdate
      • updated -> onUpdated
      • beforeDestroy -> onBeforeUnmount
      • destroyed -> onUnmounted
      • errorCaptured -> onErrorCaptured
    • 新增的鉤子函數(shù)
      • onRenderTracked
      • onRenderTriggered

    兩個(gè)鉤子函數(shù)都接收一個(gè)DebuggerEvent,與 watchEffect 參數(shù)選項(xiàng)中的 onTrack 和 onTrigger 類似:

    export?default?{??onRenderTriggered(e)?{????debugger????//?檢查哪個(gè)依賴性導(dǎo)致組件重新渲染??},}

    依賴注入

    ?

    provide 和 inject 提供依賴注入,功能類似 2.x 的 provide/inject。兩者都只能在當(dāng)前活動(dòng)組件實(shí)例的 setup() 中調(diào)用。

    ?

    這是本篇文章的重點(diǎn)。結(jié)合項(xiàng)目實(shí)戰(zhàn)以此來(lái)探索一下未來(lái)的 Vue 狀態(tài)管理模式和邏輯復(fù)用模式。

    「用法」

    ?

    provide 和 inject 提供依賴注入,功能類似 2.x 的 provide/inject。兩者都只能在當(dāng)前活動(dòng)組件實(shí)例的 setup() 中調(diào)用。

    ?

    import?{?provide,?inject?}?from?'vue'const?ThemeSymbol?=?Symbol()const?Ancestor?=?{??setup()?{????provide(ThemeSymbol,?'dark')??},}const?Descendent?=?{??setup()?{????const?theme?=?inject(ThemeSymbol,?'light'?/*?optional?default?value?*/)????return?{??????theme,????}??},}

    inject 接受一個(gè)可選的的默認(rèn)值作為第二個(gè)參數(shù)。如果未提供默認(rèn)值,并且在 provide 上下文中未找到該屬性,則 inject 返回 undefined。

    • 「注入的響應(yīng)性」

    可以使用 ref 來(lái)保證 provided 和 injected 時(shí)間值的響應(yīng):

    //?提供者:const?themeRef?=?ref('dark')provide(ThemeSymbol,?themeRef)//?使用者:const?theme?=?inject(ThemeSymbol,?ref('light'))watchEffect(()?=>?{??console.log(`theme?set?to:?${theme.value}`)})

    如果注入一個(gè)響應(yīng)式對(duì)象,則它的狀態(tài)變化也可以被偵聽(tīng)。

    邏輯組合與復(fù)用

    引出問(wèn)題:

    我們通常會(huì)基于一堆相同的數(shù)據(jù)進(jìn)行花樣呈現(xiàn),有列表展示、有餅圖占比、有折線圖趨勢(shì)、有熱力圖說(shuō)明頻次等等,這些組件使用的是相同的一些數(shù)據(jù)和數(shù)據(jù)處理邏輯。對(duì)于數(shù)據(jù)處理邏輯,目前vue有

    • Mixins
    • 高階組件 (Higher-order Components, aka HOCs)
    • Renderless Components (基于 scoped slots / 作用于插槽封裝邏輯的組件)

    但是上面的方案是存在一些弊端:

  • 模版中的數(shù)據(jù)來(lái)源不清晰
  • 命名空間沖突。
  • 需要額外的組件實(shí)例嵌套來(lái)封裝邏輯(性能問(wèn)題);
  • #####?基于組合api?的解決方案function?useMouse()?{??const?x?=?ref(0)??const?y?=?ref(0)??const?update?=?e?=>?{????x.value?=?e.pageX????y.value?=?e.pageY??}??onMounted(()?=>?{????window.addEventListener('mousemove',?update)??})??onUnmounted(()?=>?{????window.removeEventListener('mousemove',?update)??})??return?{?x,?y?}}//?在組件中使用該函數(shù)const?Component?=?{??setup()?{????const?{?x,?y?}?=?useMouse()????//?與其它函數(shù)配合使用????const?{?z?}?=?useOtherLogic()????return?{?x,?y,?z?}??},??template:?`{{?x?}}?{{?y?}}?{{?z?}}`}

    項(xiàng)目預(yù)覽

    源碼:https://github.com/961998264/todolist-vue-3.0

    項(xiàng)目介紹

  • 已完成事件列表
  • 未完成事件列表
  • 查看事件詳情
  • 修改事件完成狀態(tài)和事件詳情
  • 項(xiàng)目src目錄

    hooks文件夾是專門放hook的

    context文件夾以模塊劃分

    先來(lái)看下context編寫(xiě)(我這邊是用的ts)

    import?{?provide,?ref,?Ref,?inject,?computed,?}?from?'vue'?//vue?apiimport?{?getListApi?}?from?'api/home'?//?mock的api//?以下為定義的ts類型,你也可以單獨(dú)建一個(gè)專門定義類型的文件。type?list?=?listItem[]interface?listItem?{??title:?string,??context:?string,??id:?number,??status:?number,}interface?ListContext?{??list:?Ref,??getList:?()?=>?{},??changeStatus:?(id:?number,?status:?number)?=>?void,??addList:?(item:?listItem)?=>?void,??delList:?(id:?number)?=>?void,??finished:?Ref,??unFinish:?Ref,??setContext:?(id:?number,?context:?string)?=>?void,??setActiveItem:?()?=>?void,}

    provide名稱,推薦用Symbol

    const?listymbol?=?Symbol()

    提供provide的函數(shù)

    export?const?useListProvide?=?()?=>?{??//?全部事件???const?list?=?ref([]);??//?當(dāng)前查看的事件id??const?activeId?=?ref(null)??//?當(dāng)前查看的事件??const?activeItem?=?computed(()?=>?{????if?(activeId.value?||?activeId.value?===?0)?{??????const?item?=?list.value.filter((item:?listItem)?=>?item.id?===?activeId.value)??????return?item[0]????}?else?{??????return?null????}??})??//?獲取list??const?getList?=?async?function?()?{????const?res:?any?=?await?getListApi()????console.log("useListProvide?->?res",?res)????if?(res.code?===?0)?{??????list.value?=?res.data????}??}??//?新增list??const?addList?=?(item:?listItem)?=>?{????list.value.push(item)??}??//修改狀態(tài)??const?changeStatus?=?(id:?number,?status:?number)?=>?{????console.log('status',?status)????const?removeIndex?=?list.value.findIndex((listItem:?listItem)?=>?listItem.id?===?id)????if?(removeIndex?!==?-1)?{??????list.value[removeIndex].status?=?status????}??};??//?修改事件信息??const?setContext?=?(id:?number,?context:?string)?=>?{????const?Index?=?list.value.findIndex((listItem:?listItem)?=>?listItem.id?===?id)????if?(Index?!==?-1)?{??????list.value[Index].context?=?context????}??}??//?刪除事件??const?delList?=?(id:?number)?=>?{????console.log("delList?->?id",?id)????for?(let?i?=?0;?i??{????return?list.value.filter(item?=>?item.status?===?0)??})??//?已完成事件列表??const?finished?=?computed(()?=>?{????return?list.value.filter(item?=>?item.status?===?1)??})????provide(listymbol,?{????list,????unFinish,????finished,????changeStatus,????getList,????addList,????delList,????setContext,????activeItem,????activeId??})}

    在這個(gè)函數(shù)中定義 待辦事件,并且定義一系列增刪改查函數(shù),通過(guò)provide暴露出去。

    提供inject的函數(shù)

    export?const?useListInject?=?()?=>?{??const?listContext?=?inject(listymbol);??if?(!listContext)?{????throw?new?Error(`useListInject?must?be?used?after?useListProvide`);??}??return?listContext};

    全局狀態(tài)肯定不止一個(gè)模塊,所以在 context/index.ts 下做統(tǒng)一的導(dǎo)出

    import?{?useListProvide,?useListInject?}?from?'./home/index'console.log("useListInject",?useListInject)export?{?useListInject?}export?const?useProvider?=?()?=>?{??useListProvide()}

    然后在 App.vue 的根組件里使用 provide,在最上層的組件中注入全局狀態(tài)。

    import { useProvider } from './context/index'export default { name: 'App', setup () { useProvider() return { } }}

    在組件中獲取數(shù)據(jù):

    import?{?useListInject?}?from?'../../context/home/index'setup?()?{??const?{?list,?changeStatus,?getList,?unFinish,?finished,?addList,?a???ctiveItem,?setContext?}?=?useListInject()}

    不管是父子組件還是兄弟組件,或者是比關(guān)系套更深的組件,我們都可以通過(guò)useListInject來(lái)獲取到相應(yīng)式的數(shù)據(jù)。

  • 「邏輯聚合」 同一份數(shù)據(jù)的相關(guān)邏輯我們可以寫(xiě)在一個(gè)usexxxx的函數(shù)中,不再像以前,按照選擇將邏輯分開(kāi)。在methods,computed,watch,created,mounted中來(lái)回跳轉(zhuǎn)。
  • 「取代vuex」 在比較小的項(xiàng)目中,你可以用這種狀態(tài)管理的方式取代vuex。(反正我用react基本不用redux,不管項(xiàng)目大小)。
  • 作者:Mingle

    轉(zhuǎn)發(fā)鏈接:https://mp.weixin.qq.com/s/iOq-eeyToDXJ6lvwnC12DQ

    總結(jié)

    以上是生活随笔為你收集整理的onmounted vue3_基于项目时间阐述vue3.0新型状态管理和逻辑复用方式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。